Help us shape the future of Go! Take the 2026 Go Developer Survey

async

package
v0.23.2 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package async 提供安全的 goroutine 启动工具。

适用于所有使用此包的后端服务,防止 goroutine panic 导致进程崩溃。

核心特性

  • 自动 recover panic 并记录堆栈
  • 支持共享 channel 收集错误(GoSafeWithErrChannel)
  • 一行代码替代 go func(){...}()

快速接入

替代裸 go 关键字:

async.GoSafe(func() {
    doSomething()
})

需要收集多个 goroutine 的错误到同一 channel 时:

ch := make(chan error, 10)
async.GoSafeWithErrChannel(ch, func() error {
    return doSomething()
})

错误只需日志上报的后台任务:

async.GoSafeWithErr(func() error {
    return flushBatch(ctx)
})

携带 context 的安全 goroutine:

async.GoWithContext(ctx, func(ctx context.Context) { doWork(ctx) })
async.GoSafeWithContext(ctx, func(ctx context.Context) error { return doWork(ctx) })

命名后台任务(panic 日志带 task 标签,可按任务聚合告警):

async.GoSafeLabeled("janitor", func() { sweep() })
async.RunSafeLabeled("batch-flush", func() { flush() })

使用场景

  • 后台任务:日志上报、指标采集、缓存预热
  • 并发请求:同时调用多个下游服务
  • 异步处理:消息发送、文件处理

Panic 处理

panic 被 recover 后会:

  1. 记录 panic 信息和完整堆栈到日志
  2. GoSafeWithErrChannel 会将 panic 转为 error 发送到共享 channel
  3. 不会影响主 goroutine 的正常运行

为什么使用标准库 log 而非 logx

本包是使用方的 panic 兜底层,必须保持零内部依赖(依赖叶子节点)。 logx 会间接依赖 middleware、ratelimit 等上层包,而这些包又依赖 async, 若 async 反向依赖 logx 将形成导入环。因此本包刻意使用标准库 log。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GoSafe

func GoSafe(fn func())

GoSafe launches a goroutine with panic recovery.

func GoSafeLabeled added in v0.5.0

func GoSafeLabeled(task string, fn func())

GoSafeLabeled 与 GoSafe 相同,但 panic 汇报带任务归属标签。 后台循环 / 心跳 / 清扫等命名任务用本变体,运维可直接按 task 聚合。

func GoSafeWithContext

func GoSafeWithContext(ctx context.Context, fn func(ctx context.Context) error)

GoSafeWithContext 启动一个携带 ctx 的安全 goroutine,fn 返回的 error (含 panic 转换的 error)经 PanicHandler 记录。等价 GoWithContext + 错误上报。

func GoSafeWithContextLabeled added in v0.5.0

func GoSafeWithContextLabeled(ctx context.Context, task string, fn func(ctx context.Context))

GoSafeWithContextLabeled 启动带 ctx 的安全 goroutine,panic 汇报带任务归属标签。

func GoSafeWithErr

func GoSafeWithErr(fn func() error)

GoSafeWithErr 启动一个带 panic 恢复的 goroutine 执行 fn。 fn 返回的 error(含 panic 转换的 error)经 PanicHandler 记录后丢弃—— 适合"错误只需日志上报"的后台任务;需要收集错误到共享 channel 用 GoSafeWithErrChannel,需要同步等待/级联取消用 concurrency/group。

func GoSafeWithErrChannel

func GoSafeWithErrChannel(ch chan<- error, fn func() error)

GoSafeWithErrChannel 启动 fn 并把 panic 与 fn 返回值都发送到共享 channel。

用于需要收集多个 goroutine 的错误到同一 channel 的场景(如 concurrency/group)。 调用方需保证 ch 缓冲足够大(建议至少为参与 goroutine 的数量),避免阻塞。 发送始终非阻塞;若 channel 已满或已被调用方关闭,不阻塞、不崩溃, 相关 panic 经 PanicHandler 输出。调用方应避免在还有 goroutine 未返回时关闭 ch。

func GoWithContext

func GoWithContext(ctx context.Context, fn func(ctx context.Context))

GoWithContext 启动一个携带 ctx 的安全 goroutine(panic 恢复,无错误上报)。 fn 收到的就是调用方传入的 ctx,取消/超时由调用方管理。

func ReportPanic added in v0.5.0

func ReportPanic(r any)

ReportPanic 将一次「已被调用方 recover 的 panic」上报给全局 PanicHandler, 供自管 recover 的编排原语(如 syncx.FanInErr 逐槽收编)保持与 GoSafe/RunSafe 统一的观测面——handler 注入方(日志/告警)不漏接任何恢复事件。 msg 形如 "panic recovered: <payload>";stack 取当前调用栈。

func RunSafe added in v0.4.0

func RunSafe(fn func())

RunSafe 在当前 goroutine 同步运行 fn,panic 被 recover 并经 PanicHandler 汇报(不重新 panic)。适合"第三方回调不应打死调用方"的场景,如批量执行器 执行用户回调;需要独立 goroutine 用 GoSafe。

func RunSafeErr added in v0.6.0

func RunSafeErr(fn func() error) (err error)

RunSafeErr 同步运行 fn,panic 收编为 error 返回(不再静默)。 适合「panic → 领域 error 透给调用方」场景(如 guardedCall)。 正常返回值原样透传;panic 时额外经 PanicHandler 汇报。

func RunSafeLabeled added in v0.5.0

func RunSafeLabeled(task string, fn func())

RunSafeLabeled 与 RunSafe 相同,但 panic 汇报带任务归属标签。 msg 形如 "task=janitor: boom",便于按任务维度聚合告警,不依赖堆栈解析。 task 为空时退化为 RunSafe 的消息格式。

func RunSafeRet added in v0.6.0

func RunSafeRet[T any](fn func() (T, error)) (val T, err error)

RunSafeRet 同步运行返回 (T, error) 的 fn,panic 收编为 error(零值 T)。 调用方能区分「合法零值 + nil」与「panic 失败」。

func RunSafeRetLabeled added in v0.6.0

func RunSafeRetLabeled[T any](task string, fn func() (T, error)) (val T, err error)

RunSafeRetLabeled 同 RunSafeRet,panic 汇报带任务归属标签。

func RunSafeRetWith added in v0.7.0

func RunSafeRetWith[T any](r Runner, fn func() (T, error)) (val T, err error)

RunSafeRetWith 是 Runner 版的 RunSafeRet(方法不能带类型参数, 泛型形态以包级函数提供)。

func SetPanicHandler

func SetPanicHandler(handler PanicHandler)

SetPanicHandler 设置全局 panic 恢复日志处理器。 应在 main.go 初始化阶段调用,注入 logx 等结构化日志实现。

用法:

async.SetPanicHandler(func(msg string, stack []byte) {
    logx.Error("goroutine panic", "error", msg, "stack", string(stack))
})

Types

type PanicError added in v0.7.0

type PanicError struct {
	// Value 是 recover() 的原始值。
	Value any
	// Stack 是 panic 时的调用栈(debug.Stack(),与 PanicHandler 收到的同一份)。
	Stack []byte
	// Task 是 Labeled 变体的任务标签;非 Labeled 为空。
	Task string
}

PanicError 是 panic 收编为 error 的统一载体(#12)。

RunSafeErr / RunSafeRet / RunSafeRetLabeled 的 panic 分支、syncx.FanInErr 的逐槽收编、singleflight.Flight 的 waiter 错误路径均使用本类型——调用方 用 errors.As 即可区分「panic 失败」与「业务错误」,拿到原始 payload 与栈, 再按自己的 logger 补挂领域上下文后决定降级或透传。

Error() 文案与历史实现一致("panic: <Value>";Labeled 变体 "task=<Task>: panic: <Value>"),现有字符串匹配零破坏。

func NewPanicError added in v0.7.0

func NewPanicError(r any) *PanicError

NewPanicError 供包内其他收编点(syncx.FanInErr 逐槽、singleflight waiter) 构造统一载体;外部消费方一般不需要——错误已经从 RunSafe*/Slot.Err 拿到。

func (*PanicError) Error added in v0.7.0

func (e *PanicError) Error() string

type PanicHandler

type PanicHandler func(msg string, stack []byte)

PanicHandler 是 panic 恢复时的日志处理函数。 默认使用标准库 log.Printf。可通过 SetPanicHandler 注入自定义实现(如 logx)。

type Runner added in v0.7.0

type Runner struct {
	// Handler 本实例的 panic 汇报函数;nil 回退全局 PanicHandler。
	Handler PanicHandler
}

Runner 携带自己的 PanicHandler 的 GoSafe/RunSafe 家族(#13)。

服务形态消费方继续用包级函数 + SetPanicHandler(进程入口一次); 库形态消费方(被宿主 import,不能动全局)在包级持有一个 Runner, panic 路由到自己的组件 logger,宿主的全局设置不受影响、互不覆盖。 零值 Runner 回退全局 handler(与包级函数行为一致)。

用法:

var runner = async.Runner{Handler: func(msg string, stack []byte) {
    logx.Error("agentkit.worker.task_panic", "msg", msg, "stack", string(stack))
}}

runner.GoSafeLabeled("claim", func() { ... })
err := runner.RunSafeErr(func() error { ... })

func (Runner) GoSafe added in v0.7.0

func (r Runner) GoSafe(fn func())

GoSafe 启动带 panic 恢复的 goroutine(汇报走本实例 handler)。

func (Runner) GoSafeLabeled added in v0.7.0

func (r Runner) GoSafeLabeled(task string, fn func())

GoSafeLabeled 带 task 标签的 GoSafe(msg 形如 "task=janitor: ...")。

func (Runner) GoWithContext added in v0.7.0

func (r Runner) GoWithContext(ctx context.Context, fn func(ctx context.Context))

GoWithContext 启动携带 ctx 的安全 goroutine(汇报走本实例 handler)。

func (Runner) RunSafe added in v0.7.0

func (r Runner) RunSafe(fn func())

RunSafe 同步运行 fn,panic 经本实例 handler 汇报(不重新 panic)。

func (Runner) RunSafeErr added in v0.7.0

func (r Runner) RunSafeErr(fn func() error) (err error)

RunSafeErr 同步运行 fn,panic 收编为 *PanicError 返回并经本实例 handler 汇报。

Jump to

Keyboard shortcuts

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