4

I'm using the Redis component in my Camel application. One issue is that it automatically prepends strings to keys. For example, let's say I run the following in my Camel app:

        from("direct://path/to/store/in/redis")
            .setHeader(RedisConstants.COMMAND, constant("SET"))
            .setHeader(RedisConstants.KEY, constant("key"))
            .setHeader(RedisConstants.VALUE, constant("value"))
            .to(spring-redis://localhost:6379);

Then, if I open my command-line Redis client and run the following to list all keys in the DB:

> keys *

it returns:

1) "\xac\xed\x00\x05t\x00\x03key"

Here you can see that it prepended \xac\xed\x00\x05t\x00\x03 to the key, and I'm not sure where exactly it does that.

This wouldn't be a problem if I was only using the GET and SET Redis commands, because for some reason it prepends the same string to the key for these commands, so there's no key mis-match. However, if I try to perform a different Redis command, like KEYS, through the Camel app, like this:

from("direct://some/other/path/to/redis")
        .setHeader(RedisConstants.COMMAND, constant("KEYS"))
        .setHeader(RedisConstants.PATTERN, constant("*"))
        .to(spring-redis://localhost:6379);

it prepends a slightly different string to the asterisk, which results in the query not returning anything because there are no matches to the pattern. That is, the

> KEYS * 

command translates to something like the following in Redis:

> KEYS "\xac\xed\x00\x05t\x00\x05t*" 

Any thoughts on this?

Kenster
  • 23,465
  • 21
  • 80
  • 106
Khaled
  • 644
  • 1
  • 8
  • 14

2 Answers2

2

The following two posts helped me solve this:

Redis serialization prefixed with extra string

Weird redis key with spring data Jedis

So I fixed it by setting the DefaultRedisSerializer in RedisTemplate to StringRedisSerializer.

Since I'm using Guice for dependency/bean injection, I added the following to my GuiceCamelModule:

public class GuiceCamelTestModule extends CamelModuleWithMatchingRoutes {

    ...

    @Provides
    @JndiBind("redisTemplateBean")
    Object provideRedisTemplateBean() {
        JedisConnectionFactory redisConnectionFactory = new  JedisConnectionFactory();
        redisConnectionFactory.afterPropertiesSet();

        RedisTemplate<?, ?> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        template.setDefaultSerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
}

And my route URI looks like this:

"spring-redis://localhost:6379?redisTemplate=#redisTemplateBean"
Community
  • 1
  • 1
Khaled
  • 644
  • 1
  • 8
  • 14
1

If you are using the camel component spring-redis alone (ie without Jedis), then use the below code.

pom.xml

   <dependency>
      <groupId>org.apache.camel.springboot</groupId>
      <artifactId>camel-spring-redis-starter</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

RedisConfiguration.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfiguration {

  @Bean("redisTemplate")
  public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {

    RedisTemplate<String, Object> template = new RedisTemplate<>();

    template.setConnectionFactory(connectionFactory);

    template.setKeySerializer(new StringRedisSerializer());
    template.setHashKeySerializer(new StringRedisSerializer());
    template.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));

    return template;
  }
}

Route.java

.setHeader(RedisConstants.COMMAND, constant("SETEX"))
.setHeader(RedisConstants.KEY, simple("${body.parentId}"))
.setHeader(RedisConstants.VALUE, simple("${body}"))
.setHeader(RedisConstants.TIMEOUT, constant(100))
.to("spring-redis://" + redisHost + ":" + redisPort + "?redisTemplate=#redisTemplate");
Arjun Sunil Kumar
  • 1,781
  • 3
  • 28
  • 46