Go类型的Redis流
有效地读取Redis流需要一些工作:计算ID、预取和缓冲、异步发送确认和解析条目。如果仅仅是以下这些呢?
consumer := NewGroupConsumer[MyType](...)
for msg := range consumer.Chan() {
// Handle mssage
consumer.Ack(msg)
}
等等......是这样的!🔥
快速启动
定义一个代表你的流数据的类型。它将被自动解析,所有字段名都被转换成蛇形大小写。缺少的字段将被无声地跳过。你也可以使用ConvertibleFrom 和ConvertibleTo 接口来进行自定义解析。
// maps to {"name": , "priority": }
type Event struct {
Name string
Priority int
}
消耗者
消耗者允许通过Go通道读取redis流。指定上下文、redis客户端和开始读取的位置。如果你不喜欢默认的或者想获得最佳性能,请确保指定StreamConsumerConfig 。新条目是异步获取的,以提供快速流🚂。
consumer := NewConsumer[Event](ctx, rdb, StreamIDs{"my-stream": "$"})
for msg := range cs.Chan() {
if msg.Err != nil {
continue
}
var event Event = msg.Data
}
不要忘记Close() 消费者。如果你想从你离开的地方重新开始阅读,你可以保存最后的StreamIDs:
ids := cs.Close()
组消费者
它们的工作方式与普通消费者一样,允许异步发送确认。请注意,只有当你不断处理新的消息时,才可以使用Ack ,也就是在一个消费循环中或从另一个goroutine中。尽管这引入了一个两边的依赖,但消费者可以避免死锁:
cs := NewGroupConsumer[Event](ctx, rdb, "group", "consumer", "stream", ">")
for msg := range cs.Chan() {
cs.Ack(msg)
}
停止处理了?检查你的错误 🔎
// Wait for all acknowledgements to complete
errors := cs.AwaitAcks()
// Acknowledgements that were not sent yet or their errors were not consumed
remaining := cs.Close()
错误处理
这是简单的地方,但也只是简单的地方 🙂 通道不仅提供值,还提供错误。这些错误只能有三种类型:
ReadError报告一个失败的XRead/XReadGroup请求。消费者将在这个错误后关闭通道AckError报告一个失败的XAck请求ParseError不言自明
消费者不在取消时发送错误,并立即关闭通道:
switch errv := msg.Err.(type) {
case nil: // This interface-nil comparison in safe
fmt.Println("Got", msg.Data)
case ReadError:
fmt.Println("ReadError caused by", errv.Err)
return // last message in channel
case AckError:
fmt.Printf("Ack failed %v-%v caused by %v\n", msg.Stream, msg.ID, errv.Err)
case ParseError:
fmt.Println("Failed to parse", errv.Data)
}
所有这些类型都是包装错误。例如,ParseError ,可以解包为:
- 通过
FieldParseError找出默认解析器失败的原因(例如,将字符串分配给int字段) - 捕捉自定义错误,从
ConvertibleFrom
var fpe FieldParseError
if errors.As(msg.Err, &fpe) {
fmt.Printf("Failed to parse field %v because %v", fpe.Field, fpe.Err)
}
errors.Is(msg.Err, errMyTypeFailedToParse)
流
Streams是对流中的基本redis命令的简单包装器:
stream := NewStream[Event](rdb, "my-stream")
stream.Add(ctx, Event{
Kind: "Example event",
Priority: 1,
})
安装
go get github.com/dranikpg/gtrs
Gtrs仍然处于早期阶段,可能会在进一步的版本中发生变化。
实例
- 这是一个小的例子,从三个消费者并行读取数据,并处理所有类型的错误。
性能
go test -run ^$ -bench BenchmarkConsumer -cpu=1
一个模拟的客户端的迭代成本大约是500-700ns,取决于缓冲区的大小,这使得它的吞吐量接近每秒200万条🚀。得到不好的结果?请确保在选项中设置大的缓冲区尺寸。