Как правильно связать операции redis в spring-data-redis-reactive?
В spring-data-redis-reactive
, операции записи возвращают результат выполнения redis, что значительно усложняет связывание операторов. Возьмем, к примеру, Reddit в главе 1 Redis In Action. Я пытаюсь реализовать так:
@Service
public class ArticleService {
private final ReactiveStringRedisTemplate redisTemplate;
private final long voteScore = 432L;
public ArticleService(ReactiveStringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
public Mono<Article> createArticle(Article article) {
long now = System.currentTimeMillis();
Map<String, String> newArticle = new HashMap<>();
newArticle.put("title", article.getTitle());
newArticle.put("link", article.getLink());
newArticle.put("poster", article.getPoster());
newArticle.put("time", String.valueOf(now));
newArticle.put("votes", "1");
return redisTemplate.opsForValue()
.increment("article:")
.doOnNext(id -> redisTemplate.opsForSet().add("voted:" + id.toString(), article.getPoster()).subscribe())
.doOnNext(id -> redisTemplate.expire("votes:" + id.toString(), Duration.ofDays(7)).subscribe())
.doOnNext(id -> redisTemplate.opsForHash().putAll("article:" + id.toString(), newArticle).subscribe())
.doOnNext(id -> redisTemplate.opsForZSet().add("score:", "article:" + id.toString(), now + voteScore).subscribe())
.doOnNext(id -> redisTemplate.opsForZSet().add("time:", "article:" + id.toString(), now).subscribe())
.map(id -> {
article.setId(id);
article.setVotes("1");
return article;
});
}
}
Как видите, я использую doOnNext
чтобы не потерять значение id, возвращаемое increment
, и есть subscribe()
в каждом doOnNext
чтобы убедиться, что каждая операция redis выполнена. Но я не думаю, что это рекомендуемый способ. Я считаю, что приложениям следует избегатьsubscribe()
и в основном сосредотачиваться на цепочке потока.
Как правильно выполнять многие операции записи redis в spring-data-redis-reactive
?
0 ответов
Избегайте подписки между ними, Spring подпишется на поток в конце, если вы вызываете это из веб-интерфейса. Вот пример того, как можно реализовать
return redisTemplate.opsForValue()
.increment("article:")
.flatMap(id -> // Mono.zip will execute concurrently all the modifications below
Mono.zip(redisTemplate.opsForSet().add("voted:" + id.toString(), article.getPoster()),
redisTemplate.expire("votes:" + id.toString(), Duration.ofDays(7)),
redisTemplate.opsForHash().putAll("article:" + id.toString(), newArticle),
redisTemplate.opsForZSet().add("score:", "article:" + id.toString(), now + voteScore),
redisTemplate.opsForZSet().add("time:", "article:" + id.toString(), now)
)
.map(tuple -> id))
.map(id -> {
article.setId(id);
article.setVotes("1");
return article;
});
Но вы должны подумать о внесении этих изменений в
MULTI
Команда Redis, чтобы убедиться, что это происходит атомарно https://redis.io/commands/multi. Поскольку у вас нет проверки и / или ограничений, EVAL не требуется https://redis.io/commands/eval