-
Notifications
You must be signed in to change notification settings - Fork 959
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensure atomic transactions after reconnect #695
Comments
Using the asynchronous API allows you to optimize for various aspects of the actual execution. The example optimizes for throughput (pipelining) without awaiting command completion.
In your code |
Thank you for your detailed answer! I'd like to dig a more deeper into this case. First, let me be more specific about what I meant by a race condition in the second example. Let's consider this simple example: public class Example {
private static String KEY = "key";
private static CompletionStage<TransactionResult> executeTransaction(
RedisAsyncCommands<String, String> commands, String value) {
return commands
.multi()
.thenCompose(unused -> {
// This is executed iff multi succeeds
commands.set(KEY, value);
return commands.exec();
});
}
public static void main(String[] args) {
String host = args[0];
int port = Integer.valueOf(args[1]);
RedisURI redisURI = RedisURI.Builder.redis(host, port).build();
RedisClient client = RedisClient.create(redisURI);
StatefulRedisConnection<String, String> connection = client.connect();
RedisAsyncCommands<String, String> commands = connection.async();
CompletionStage<TransactionResult> stage1 = executeTransaction(commands, "value1");
RedisFuture<String> stage2 = commands.set(KEY, "value2");
stage1.toCompletableFuture().join();
stage2.toCompletableFuture().join();
System.out.println(commands.get(KEY).toCompletableFuture().join());
connection.close();
client.shutdown();
}
} In this case the final value can be either Therefore, can I always assume that failure of
Thank you! |
The code above runs into a concurrency race anyway because you're continuing the actual transaction with a context switch. The function passed to To your questions:
Cancelling a command has no effect on the actual execution within Redis. Once a command is sent, it's going to be executed. Sending writes the command to the transport and there's no way to reverse the write. The connection is kind of blocked until execution completes. The only way for relief on the client side is to disconnect the connection and start over. |
Thank you for your answer. Again, let me clarify a couple of things:
RedisFuture<String> multi = async.multi();
RedisFuture<String> set = async.set("key", "value");
...
RedisFuture<TransactionResult> exec = async.exec(); Can you please clarify again what would happen here if the call |
See above:
|
That's what I was afraid of in the first place: isn't it a bug, that commands after reconnection are replayed without a transactional context? |
Yes, in the context of auto-reconnect it's a bug because the batch isn't atomic anymore. I adjusted the ticket accordingly. |
Thank you! Are you sure this happens only after reconnect? What about such a case: MULTI gets |
Hi, is there any update on this issue? |
Feel free to submit a pull request. This is a community-maintained driver so any contributions can accelerate when this gets fixed. |
Since this issue was not very active the last year I am putting it in the Icebox. |
I am using version 5.0.1.RELEASE.
I would like to ask about the proper way of executing transactions using asynchronous commands.
Let's take a look at the example from the wiki (modified to be consistent with 5.0.1 version):
My question is: why is the result of
MULTI
ignored? Shouldn't the rest of the commands and theEXEC
be sent after we know, thatMULTI
command was executed successfully?On the other hand, if we do it like this:
we might cause a race condition (before
MULTI
is completed, other commands might be sent and executed inside transaction).Thank you!
The text was updated successfully, but these errors were encountered: