ru.tinkoff.kora.kafka.common.producer.TransactionalPublisher Maven / Gradle / Ivy
package ru.tinkoff.kora.kafka.common.producer;
import org.apache.kafka.clients.consumer.ConsumerGroupMetadata;
import org.apache.kafka.clients.consumer.OffsetAndMetadata;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.common.TopicPartition;
import ru.tinkoff.kora.kafka.common.annotation.KafkaPublisher;
import jakarta.annotation.Nullable;
import java.util.Map;
/**
* @param publisher type that must be annotated with {@link KafkaPublisher}
*/
public interface TransactionalPublisher
{
interface Transaction
extends AutoCloseable {
P publisher();
Producer producer();
/**
* See {@link KafkaProducer#sendOffsetsToTransaction(Map, ConsumerGroupMetadata)}
*/
void sendOffsetsToTransaction(Map offsets, ConsumerGroupMetadata groupMetadata);
/**
* See {@link KafkaProducer#abortTransaction()}
*/
void abort(@Nullable Throwable t);
/**
* See {@link KafkaProducer#abortTransaction()}
*/
default void abort() {
this.abort(null);
}
/**
* See {@link KafkaProducer#flush()} ()}
*/
void flush();
@Override
void close();
}
/**
* Initialize Publisher in transaction mode {@link Producer#initTransactions()} and then begins transaction {@link Producer#beginTransaction()} and returns publisher in such state
*
* @return Publisher as {@link P}
*
* It is expected that you will manually call {@link Producer#commitTransaction()} or {@link Producer#abortTransaction()} and then {@link Producer#close()}
*/
Transaction extends P> begin();
default void inTx(TransactionalConsumer callback) throws E {
try (var p = begin()) {
try {
callback.accept(p.publisher());
} catch (Throwable e) {
p.abort();
throw e;
}
}
}
default R inTx(TransactionalFunction callback) throws E {
try (var p = begin()) {
try {
return callback.accept(p.publisher());
} catch (Throwable e) {
p.abort();
throw e;
}
}
}
default void withTx(TransactionConsumer callback) throws E {
try (var p = begin()) {
try {
callback.accept(p);
} catch (Throwable e) {
p.abort();
throw e;
}
}
}
default R withTx(TransactionFunction callback) throws E {
try (var p = begin()) {
try {
return callback.accept(p);
} catch (Throwable e) {
p.abort();
throw e;
}
}
}
@FunctionalInterface
interface TransactionalConsumer
{
void accept(P publisher) throws E;
}
@FunctionalInterface
interface TransactionalFunction
{
R accept(P publisher) throws E;
}
@FunctionalInterface
interface TransactionConsumer
{
void accept(Transaction extends P> tx) throws E;
}
@FunctionalInterface
interface TransactionFunction
{
R accept(Transaction extends P> tx) throws E;
}
}