Go Redis Hook 钩子
go-redis 允许配置 Hook,在执行命令前后可以做一些工作,也可以改变命令的参数、执行结果等。
Hook 采用 FIFO
先进先出的模式,即最先添加的 hook,最先被执行,以下是 hook 示例:
// 添加的钩子,必须实现Hook接口
// DialHook: 当创建网络连接时调用的hook
// ProcessHook: 执行命令时调用的hook
// ProcessPipelineHook: 执行管道命令时调用的hook
type Hook interface {
DialHook(next DialHook) DialHook
ProcessHook(next ProcessHook) ProcessHook
ProcessPipelineHook(next ProcessPipelineHook) ProcessPipelineHook
}
// -------- hook1
type Hook1 struct{}
func (Hook1) DialHook(next redis.DialHook) redis.DialHook {
return func(ctx context.Context, network, addr string) (net.Conn, error) {
return next(ctx, network, addr)
}
}
func (Hook1) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
return func(ctx context.Context, cmd Cmder) error {
print("hook-1 start")
next(ctx, cmd)
print("hook-1 end")
return nil
}
}
func (Hook1) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook {
return func(ctx context.Context, cmds []Cmder) error {
return next(ctx, cmds)
}
}
// -------- hook2
type Hook2 struct{}
func (Hook2) DialHook(next redis.DialHook) redis.DialHook {
return func(ctx context.Context, network, addr string) (net.Conn, error) {
next(ctx, network, addr)
}
}
func (Hook2) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
return func(ctx context.Context, cmd Cmder) error {
print("hook-2 start")
next(ctx, cmd)
print("hook-2 end")
return nil
}
}
func (Hook2) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook {
return func(ctx context.Context, cmds []Cmder) error {
return next(ctx, cmds)
}
}
// 把两个hook添加到client
client.AddHook(Hook1{}, Hook2{})
client.Get(ctx, "key")
如上所述,对 client 添加了 hook1 和 hook2,2 个钩子都对 ProcessHook
执行了 print 函数,当执行命令时,调用的顺序如下:
hook-1 start -> hook-2 start -> exec redis cmd -> hook-2 end -> hook-1 end
在这里请注意:next(...)
操作很重要,是调用下一个 hook,在 hook 调用链中,最后一个 hook 是 redis 执行命令操作。
在示例中,如果 hook1 ProcessHook 中如果不执行 next,则不会执行 hook2 也不会执行 redis 命令。
Hook 支持三个挂钩点,分别是:
- DialHook: 当创建网络连接时调用的 hook
- ProcessHook: 执行命令时调用的 hook
- ProcessPipelineHook: 执行管道命令时调用的 hook
在不同的挂钩点你可以做不同的事,可以统计命令个数计算 top key,也可以统计命令执行时间,也可以做一些其它你想要做的操作。
在 hook 函数中,可以手动为 cmd 命令设置错误和返回值,调用方将收到你设置的错误和值,这对 mock
测试很有用,在 go-redis 的 redismock 中就利用了 hook 截断要执行的命令,对命令写入了测试中期望的返回值或错误。
你也可以返回错误来终止函数,你的错误最终会传递到调用命令的地方。