Как запустить конвейер без транзакций от клиента.Функция наблюдения в go-redis
У меня есть сценарий, подобный следующему:
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/exec, что означает, что если я буду использовать ее для чтения данных (фаза 1), я потеряю защиту часов в второй конвейер, который я использую для обновления данных.
Любые решения будут приняты.
1 ответ
Вы можете использовать конвейер, используя 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 находятся на другом порту.