Claus Ibsen created CAMEL-26019:
-----------------------------------

             Summary: camel-spring-redis - unimplemented commands do nothing, 
GET of a missing key keeps the body, and more
                 Key: CAMEL-26019
                 URL: https://issues.apache.org/jira/browse/CAMEL-26019
             Project: Camel
          Issue Type: Bug
          Components: camel-spring-redis
    Affects Versions: 4.18.0, 4.22.0, 4.23.0
            Reporter: Claus Ibsen
             Fix For: 4.24.0


Found while checking the body types of the spring-redis component for the 
catalog (CAMEL-24961).

h4. 1. A command the producer does not implement does nothing and raises no 
error

A command of the {{command}} enum that the producer has no method for does 
nothing: no error, and the body stays as it was. These are AUTH, BGREWRITEAOF, 
BGSAVE, CONFIG, DBSIZE, DEBUG, FLUSHALL, FLUSHDB, INFO, LASTSAVE, MONITOR, 
PSUBSCRIBE, PUNSUBSCRIBE, RENAMEX, SAVE, SELECT, SHUTDOWN, SLAVEOF, SUBSCRIBE, 
SUBSTR, SYNC, UNSUBSCRIBE and ZSCORE (the generated 
{{RedisProducerInvokeOnHeaderFactory}} returns null for them, as it does for a 
misspelled command; the general part is in the camel-support issue).

Checked on 4.24.0-SNAPSHOT with {{camel run}} against {{camel infra run 
redis}}: after ZADD, {{CamelRedis.Command=ZSCORE}} left the body of the ZRANGE 
before it, and {{CamelRedis.Command=NOSUCH}} left the body "Hello", with no 
error.

*Proposed change*: implement ZSCORE and the other commands that make sense in a 
producer, and fail with an error that names the command for the rest (SUBSCRIBE 
and PSUBSCRIBE are consumer commands).

h4. 2. GET of a missing key keeps the body as it was

The body is set to the result of a command only when the result is not null 
({{HeaderSelectorProducer.processResult}}). So GET of a missing key leaves the 
body as it was, and so do HGET, LPOP, RPOP, LINDEX and the other commands that 
read one value: a route cannot tell a miss from a value that equals the old 
body.

Checked on 4.24.0-SNAPSHOT with {{camel run}} against {{camel infra run 
redis}}: with the body "Other body", GET of the key "nope" and HGET of a 
missing field both left "Other body".

*Proposed change*: set the body to null when a command that reads a value finds 
none (override {{processResult}} in {{RedisProducer}} for those commands), and 
say so in the docs and the upgrade guide.

h4. 3. KEYS finds nothing with the default serializer, and ECHO without a value 
fails with a NullPointerException

KEYS sends the pattern through the key serializer of the template 
({{RedisClient}}, main 07d2e7a987bc, line 359; {{RedisTemplate.keys}}), which 
is the JDK serializer by default. The serialized pattern holds its length, so 
{{*}} matches only keys of that serialized length: KEYS with {{v-*}} found 
nothing, while the keys v-text, v-bytes and others had been set with SET.

ECHO without the {{CamelRedis.Value}} header fails with {{NullPointerException: 
Cannot invoke "String.getBytes()" because "value" is null}} ({{RedisClient}}, 
line 254).

Both checked on 4.24.0-SNAPSHOT with {{camel run}} against {{camel infra run 
redis}}.

*Proposed change*: send the pattern of KEYS as a plain string (with the string 
serializer), and fail ECHO with an error that says the header is missing.

h4. 4. A message another client published is dropped with a WARN

The consumer deserializes each message with the {{serializer}}, the JDK 
serializer by default ({{RedisConsumer}}, main 07d2e7a987bc, lines 86-90). A 
message that another client published, such as {{redis-cli PUBLISH}}, is not 
Java-serialized: the consumer logs WARN "Error processing redis message ... 
Cannot deserialize" and the message is lost. The docs say the values are 
Java-serialized by default, but not that the consumer cannot read the messages 
of other clients.

Checked on 4.24.0-SNAPSHOT with {{camel run}} against {{camel infra run 
redis}}: {{docker exec camel-redis redis-cli PUBLISH outside "plain text"}} 
gave that WARN and no exchange.

*Proposed change*: say in the docs that the consumer needs 
{{serializer=#class:org.springframework.data.redis.serializer.StringRedisSerializer}}
 to read messages from other clients, and consider giving the payload as bytes 
when it cannot be deserialized.

h4. Also read in the code, not run

* SETBIT and GETBIT use the raw bytes of the key ({{RedisClient}}, lines 161 
and 168), while the other commands use the key serializer, so with the default 
serializer they work on another key than SET and GET.
* {{CamelRedis.Keys}} is documented as a String, but it is read as a Collection 
({{ExchangeConverter}}, line 98), and a String does not convert: DEL with a 
String header deletes nothing.
* MSETNX drops the Boolean result of the call ({{RedisProducer}}, lines 
525-528).
* The consumer does not check the exchange for an exception after the route 
({{RedisConsumer}}, line 80), so a failed exchange is not given to the 
exception handler.

_Claude Code on behalf of davsclaus_



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to