javaspringspring-bootspring-webfluxspring-data-redis-reactive

Can retrieve values manually set in redis-cli but unable to set new keys through Redis Reactive in Spring Boot


I'm using Spring Webflux + Reactive Redis, my goal is to use Redis as a file cache.

I was trying to set a key with a ~100MB ByteBuffer at first, didn't work. I double-checked with the debugger to make sure the file was actually being read into memory, and surely it was. I thought "maybe Redis doesn't like "big" Strings?" so I tried with the code below, still no dice. Thought maybe it could be an ACL related issue, but I checked and the default user has access to everything. "Maybe Spring can't access Redis?" nope, I checked the MONITOR output in redis-cli and the GET command is being received just fine, no signs of the SET command though. Any suggestions?

Here's my controller:

@RequestMapping(value = "/prime", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Mono<String> prime() {
    reactiveStringCommands.set(ByteBuffer.wrap("testkey2".getBytes()), ByteBuffer.wrap("test".getBytes()));

    return reactiveStringCommands.get(ByteBuffer.wrap("testkey".getBytes())).map(bb -> new String(bb.array()));
}

Relevant settings in application.properties:

spring.redis.host=localhost
spring.redis.password=<password>
spring.redis.port=6379

redis-cli output (testkey was manually set in the CLI, no signs of testkey2):

127.0.0.1:6379> keys *
1) "testkey"
127.0.0.1:6379> ACL list
1) "user default on #<password> ~* +@all"
127.0.0.1:6379> monitor
OK
1610406175.250768 [0 172.17.0.1:39104] "GET" "testkey"

Edit: Forgot to mention that there's no stack traces nor any type of error being output to the console.


Solution

  • Number one rule of reactive: nothing happens until you subscribe.

    While your code looks fine if you are looking at it from imperative perspective but it is not correct from a reactive point of view.

    The reason you don't see the impact of the set command is that there is nothing subscribing to it.

    What you need to do is to join these two statements together like below:

    public Mono<String> prime() {
        return reactiveStringCommands.set(ByteBuffer.wrap("testkey2".getBytes()), ByteBuffer.wrap("test".getBytes()))
                .then(reactiveStringCommands.get(ByteBuffer.wrap("testkey".getBytes())).map(bb -> new String(bb.array())));
    }
    

    This way Spring will internally subscribe to the resulting Mono which in turn will subscribe to all the operators/steps (including the set command) in the chain.