singleflight

package
v0.34.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package singleflight 提供并发请求合并(防击穿)工具。

fork 自 github.com/oekit/concurrency/singleflight(stdlib-only 泛型实现): pkg 是最底层模块(零 oekit 内部依赖),cache.SingleFlightCache 需要它 又不能反向依赖 concurrency,故内部化。concurrency 侧修 bug 时须同步本 fork。

同一个 key 的并发调用只执行一次 fn,其他调用共享结果。 适用于缓存穿透防护、token 刷新、配置加载等场景。

核心特性

  • 基于 sync.Map + close(chan struct{}) 实现,零外部依赖
  • 泛型支持,类型安全
  • race detector 友好
  • panic 安全:fn panic 不会导致等待者死锁

快速接入

sf := singleflight.New[string]()
val, err := sf.Do(ctx, "token:wechat_app", func(ctx context.Context) (string, error) {
    return fetchAccessToken(ctx)
})

原理

调用 Do(key, fn) 时:
 1. sync.Map.LoadOrStore 保证只有一个 goroutine 成为 caller
 2. caller 执行 fn,完成后 close(ready) 广播通知
 3. 其他 goroutine (waiter) 通过 <-ready 等待,读取共享结果
 4. close 提供 happens-before 保证,字段读取无 data race

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Flight

type Flight[T any] struct {
	// contains filtered or unexported fields
}

Flight 对同一个 key 的并发调用只执行一次 fn。 零值可用,无需初始化。

func New

func New[T any]() *Flight[T]

New 创建一个 Flight 实例。

func (*Flight[T]) Do

func (f *Flight[T]) Do(ctx context.Context, key string, fn func(ctx context.Context) (T, error)) (T, error)

Do 执行 fn,同一个 key 的并发调用共享结果。

如果多个 goroutine 同时调用 Do 且 key 相同:

  • 只有第一个 goroutine(caller)实际执行 fn
  • 其他 goroutine(waiter)阻塞等待结果
  • caller 完成后所有 waiter 同时获得返回值

panic 处理(与 golang.org/x/sync/singleflight 语义一致):

  • 若 fn panic,panic 向首个 caller 自然传播(保留原始调用栈)
  • waiter 被唤醒并拿到由 panic 转化的 error(而非零值+nil 的伪成功—— 调用方无法区分"合法零值"与"执行失败",会静默污染下游缓存/状态)
  • map 中的 key 记录会被清理,不会因 panic 残留导致后续调用死锁

func (*Flight[T]) Forget

func (f *Flight[T]) Forget(key string)

Forget 移除指定 key 的进行中调用记录。 之后对该 key 的 Do 调用会发起新的 fn 执行。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL