Skip to content

WATCH during MULTI shouldn't fail transaction #3009

Closed
@jabolina

Description

@jabolina

Bug Report

Redis returns an error if a WATCH command is submitted inside a MULTI. However, this command is silently discarded. The WATCH command does not count in the final result list during the EXEC phase. For example:

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set foo fooer
QUEUED
127.0.0.1:6379(TX)> watch some-key
(error) ERR WATCH inside MULTI is not allowed
127.0.0.1:6379(TX)> set bar baer
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK

Observe that the WATCH command is not included in the result list.

Current Behavior

Lettuce includes the failed WATCH command in the output list. Additionally, since the command is dropped, the response list has fewer responses than the command list in MultiOutput and some commands might never be completed.

Input Code

For example, adding the following test to the TransactionCommandIntegrationTests class:

Input Code
    @Test
    void watchWithinMulti() {
        redis.multi();
        redis.set("one-a", "a");
        redis.set("one-b", "b");
        redis.watch("something");
        redis.set("one-c", "c");

        TransactionResult result = redis.exec();
        for (Object o : result) {
            System.out.println(o);
        }

        assertThat(result)
                .hasSize(3)
                .allMatch("OK"::equals);
    }

Produces:

OK
OK
io.lettuce.core.RedisCommandExecutionException: ERR WATCH inside MULTI is not allowed

java.lang.AssertionError: 
Expecting all elements of:
  DefaultTransactionResult [wasRolledBack=false, responses=3]
to match given predicate but this element did not:
  io.lettuce.core.RedisCommandExecutionException: ERR WATCH inside MULTI is not allowed
	at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:152)
	at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:120)
	at io.lettuce.core.output.MultiOutput.complete(MultiOutput.java:154)
	...(25 remaining lines not displayed - this can be changed with Assertions.setMaxStackTraceElementsDisplayed)

	at io.lettuce.core.commands.TransactionCommandIntegrationTests.watchWithinMulti(TransactionCommandIntegrationTests.java:135)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

Expected behavior/code

The test should complete successfully with all 3 set operations returning an OK response.

Environment

  • Lettuce version(s): main branch

Additional context

I think WATCH is the only command that the MULTI will drop. The solution will require something specific to WATCH.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions