com.couchbase.client.java.transactions.ReactiveTransactions Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-client Show documentation
Show all versions of java-client Show documentation
The official Couchbase Java SDK
/*
* Copyright 2022 Couchbase, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.couchbase.client.java.transactions;
import com.couchbase.client.core.Core;
import com.couchbase.client.core.annotation.Stability;
import com.couchbase.client.core.transaction.CoreTransactionAttemptContext;
import com.couchbase.client.core.transaction.CoreTransactionContext;
import com.couchbase.client.core.transaction.CoreTransactionsReactive;
import com.couchbase.client.core.transaction.config.CoreMergedTransactionConfig;
import com.couchbase.client.core.transaction.config.CoreTransactionOptions;
import com.couchbase.client.core.transaction.threadlocal.TransactionMarker;
import com.couchbase.client.core.transaction.threadlocal.TransactionMarkerOwner;
import com.couchbase.client.core.transaction.util.CoreTransactionsSchedulers;
import com.couchbase.client.java.codec.JsonSerializer;
import com.couchbase.client.java.transactions.config.TransactionOptions;
import com.couchbase.client.java.transactions.error.TransactionFailedException;
import com.couchbase.client.java.transactions.internal.ErrorUtil;
import reactor.core.publisher.Mono;
import reactor.util.annotation.Nullable;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* An asynchronous version of {@link Transactions}, allowing transactions to be created and run in an asynchronous
* manner.
*
* The main method to run transactions is {@link ReactiveTransactions#run}.
*/
public class ReactiveTransactions {
private final CoreTransactionsReactive internal;
private final JsonSerializer serializer;
@Stability.Internal
public ReactiveTransactions(Core core, JsonSerializer serializer) {
Objects.requireNonNull(core);
this.internal = new CoreTransactionsReactive(core, core.context().environment().transactionsConfig());
this.serializer = Objects.requireNonNull(serializer);
}
/**
* Runs the supplied transactional logic until success or failure.
*
* This is the asynchronous version of {@link Transactions#run}, so to cover the differences:
*
* - The transaction logic is supplied with a {@link CoreTransactionAttemptContext}, which contains asynchronous
* methods to allow it to read, mutate, insert and delete documents.
* - The transaction logic should run these methods as a Reactor chain - as standard with reactive programming.
* - The transaction logic should return a
Mono{@literal <}Void{@literal >}
. Any
* Flux
or Mono
can be converted to a Mono{@literal <}Void{@literal >}
by
* calling .then()
on it.
* - This method returns a
Mono{@literal <}TransactionResult{@literal >}
, which should be handled
* as a normal Reactor Mono.
*
*
* @param transactionLogic the application's transaction logic
* @param options the configuration to use for this transaction
* @return there is no need to check the returned {@link TransactionResult}, as success is implied by the lack of a
* thrown exception. It contains information useful only for debugging and logging.
* @throws TransactionFailedException or a derived exception if the transaction fails to commit for any reason, possibly
* after multiple retries. The exception contains further details of the error.
*/
public Mono run(Function> transactionLogic,
@Nullable TransactionOptions options) {
return internal.run((ctx) -> transactionLogic.apply(new ReactiveTransactionAttemptContext(ctx, serializer)), options == null ? null : options.build())
.onErrorResume(ErrorUtil::convertTransactionFailedInternal)
.map(TransactionResult::new);
}
/**
* Convenience overload that runs {@link ReactiveTransactions#run} with a default PerTransactionConfig
.
*/
public Mono run(Function> transactionLogic) {
return run(transactionLogic, null);
}
TransactionResult runBlocking(Consumer transactionLogic, @Nullable CoreTransactionOptions perConfig) {
return Mono.defer(() -> {
CoreMergedTransactionConfig merged = new CoreMergedTransactionConfig(internal.config(), Optional.ofNullable(perConfig));
CoreTransactionContext overall =
new CoreTransactionContext(internal.core().context(),
UUID.randomUUID().toString(),
merged,
internal.core().transactionsCleanup());
// overall.LOGGER.info(configDebug(config, perConfig, cleanup.clusterData().cluster().core()));
Mono createAttempt = Mono.defer(() -> {
String attemptId = UUID.randomUUID().toString();
return Mono.just(internal.createAttemptContext(overall, merged, attemptId));
});
Function> newTransactionLogic = (ctx) -> Mono.defer(() -> {
TransactionAttemptContext ctxBlocking = new TransactionAttemptContext(ctx, serializer);
return Mono.fromRunnable(() -> {
TransactionMarkerOwner.set(new TransactionMarker(ctx));
try {
transactionLogic.accept(ctxBlocking);
}
finally {
TransactionMarkerOwner.clear();
}
})
.subscribeOn(internal.core().context().environment().transactionsSchedulers().schedulerBlocking())
.then();
});
return internal.executeTransaction(createAttempt, merged, overall, newTransactionLogic, false)
.onErrorResume(ErrorUtil::convertTransactionFailedInternal);
}).map(TransactionResult::new)
.publishOn(internal.core().context().environment().transactionsSchedulers().schedulerBlocking()).block();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy