Как запустить конвейер без транзакций из client.Watch в go -redis - PullRequest
1 голос
/ 10 января 2020

У меня есть сценарий, подобный следующему:

txf := func(tx *redis.Tx) error {
  // Phase 1:  
  // read some stuff by several get/hget request which I want to send with pipeline
  // to avoid unnecessarily rounds to the redis server 

  // Phase 2: Prepare new data based on read data

  // Phase 3: Write the new data with a transaction to use the watch protection if original keys changed
  _, err = tx.Pipelined(func(pipe redis.Pipeliner) error {
             // pipe handles the error case
             pipe.Set(key, value, 0)
             return nil})
  return err
}
err := client.Watch(txf, key)

Из чтения кода библиотеки кажется, что tx.TxPipeline и tx.Pipeline оба возвращают в этом случае реализацию multi / exe c, которая означает, что если я буду использовать его для чтения данных (фаза 1), я потеряю защиту часов во втором конвейере, который я использую для обновления данных.
Будут оценены любые решения.

1 Ответ

1 голос
/ 10 января 2020

Вы можете использовать конвейер, используя client.Pipelined(... вместо tx..Pipelined(..., но он будет отправлен на сервер redis с использованием другого соединения из пула go -redis (другой клиент с точки зрения сервера redis). Я не думаю, что это проблема.

go-redis транзакции используют липкое соединение, чтобы гарантировать, что вся транзакция, начиная с WATCH, отправляется с того же соединения. Внутренний tx.baseClient не экспортируется. Невозможно отправить конвейер с использованием того же соединения.

txf := func(tx *redis.Tx) error {
  // Phase 1:  
  var getPipe *redis.StringCmd
  cmds, err := client.Pipelined(func(pipe redis.Pipeliner) error {
        getPipe = pipe.Get("getPipe")
        pipe.Set("pipe1", "p1", 0)
        return nil
  })
  fmt.Println(getPipe)
  fmt.Println(cmds)
  val, _ := getPipe.Result()
  fmt.Println("Value read for 'getPipe':", val)

  // Phase 2: Prepare new data based on read data

  // Phase 3
  _, err = tx.Pipelined(func(pipe redis.Pipeliner) error {
    // pipe handles the error case
    pipe.Set(key, value, 0)
    return nil})
  return err
}
err := client.Watch(txf, key)
fmt.Println(client.Get(key), err)

Вывод вышеуказанной программы go:

get getPipe: preVal
[get getPipe: preVal set pipe1 p1: OK]
Value read for 'getPipe': preVal
get myKey: insideMulti <nil>

И это то, что я вижу с MONITOR команда на redis-cli:

1 ...1:65506] "watch" "myKey"
2 ...1:65507] "get" "getPipe"
3 ...1:65507] "set" "pipe1" "p1"
4 ...1:65506] "MULTI"
5 ...1:65506] "set" "myKey" "insideMulti"
6 ...1:65506] "EXEC"
7 ...1:65506] "unwatch"
8 ...1:65506] "get" "myKey"

Примечание: строки 2 и 3 находятся на другом порту

...