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

lynx

package module
v1.20.0 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 2026 License: Apache-2.0 Imports: 22 Imported by: 20

README

Lynx

Go Version License

Lynx 是一个轻量级 Go 微服务框架:统一的应用生命周期、Service 插件化架构,以及 HTTP/gRPC、EventBus、配置、健康检查与可选的注册发现 / 可观测性扩展。

特性

  • 生命周期 — 启动 / 排水(Drain)/ 优雅关闭;OnPreStart / OnPostStart / OnDrain / OnPreStop / OnPostStop 钩子
  • 服务系统 — Service + ServiceFactory;实现 Checker 的服务自动进入健康检查
  • HTTP / gRPC — 内置服务器与客户端(otel、请求日志、健康端点、中间件;默认 request_id / user_id 传播,HTTP 头与 gRPC metadata 同源)
  • EventBus — 一等 Bus / Topic[T] / Event[T],默认内存开箱即用
  • 跨进程消息 — contrib/watermill Bus + contrib/watermill-kafka Transport
  • 配置 — Config / ConfigSource 与具体库解耦,默认适配 Viper
  • 可观测性 — OpenTelemetry(contrib/telemetry)、pprof(debug)
  • 可测试性 — lynxtest 三层测试套件(组装测试 / 服务级 AppContext / 拨号辅助)
  • 扩展 — 注册发现(registry / consul)、Cron(schedule)、Zap(zap)、CLI、Wire

安装

要求 Go 1.26.5+:

go get github.com/lynx-go/lynx

快速开始

HTTP 服务
package main

import (
	"encoding/json"
	gohttp "net/http"

	"github.com/lynx-go/lynx"
	"github.com/lynx-go/lynx/server/http"
)

func main() {
	lynx.NewRunner(func(app lynx.App) error {
		mux := gohttp.NewServeMux()
		mux.HandleFunc("/", func(w gohttp.ResponseWriter, r *gohttp.Request) {
			meta := lynx.Meta(app.Context())
			_ = json.NewEncoder(w).Encode(map[string]any{
				"hello": "world",
				"from":  meta.Name,
				"id":    meta.ID,
			})
		})
		app.Register(http.NewServer(mux,
			http.WithAddr(":8080"),
			http.WithHealthCheckers(app.HealthCheckers),
		))
		return nil
	},
		lynx.WithName("my-app"),
		lynx.WithVersion("1.0.0"),
	).Run()
}
go run main.go
  • 业务:http://localhost:8080
  • 存活 / 就绪:/healthz/liveness、/healthz/readiness
  • 服务端默认安装 request_id / user_id 传播:合法的 x-request-id / x-user-id 还原进请求 ctx 并回写响应头(WithDisableRequestID() 关闭)

更多完整示例见 _examples/http。

配置

默认已绑定常用 flags(可用 WithDisableConfigFlags() 关闭;子命令框架等外部解析场景用 WithConfigFile(path) 绑定路径并关闭默认解析):

-c, --config string       配置文件路径
    --config-type string  文件类型(默认 yaml)
    --config-dir string   配置目录
    --log-level string    日志级别

应用元数据键:service.name / service.id / service.version。
日志级别:logging.level 为规范键(log-level/log_level 为仅配置文件的兼容回退,已废弃);--log-level 显式传参时覆盖配置,自定义级别 flag 须在 WithBindConfigFunc 里翻译进规范键(见 _examples/boot)。

通过 app.Config() 读取(Get / 类型化 getter / Unmarshal)。绑定阶段使用 ConfigSource(Set / SetFile / BindEnv 等);默认实现适配 *viper.Viper。

EventBus

默认内存 Bus 由框架注入,无需 Register。业务以 Topic[T] 为主路径;Bus 解析顺序:eventbus.WithBus → Context → Default()。

import "github.com/lynx-go/lynx/eventbus"

var UserCreated = eventbus.NewTopic[User]("user.created")

// 订阅(Init / OnStart;handler 名用 Option,省略时默认为 topic)
err := UserCreated.Subscribe(ctx,
	func(ctx context.Context, e *eventbus.Event[User]) error {
		// e.Payload 已是 User
		return nil
	}, eventbus.WithHandlerName("notify"))

// 发布(自动 JSON 序列化);返回值即消息 ID——与订阅端 Event.ID 相同,
// 生产/消费两端日志可凭此对账;也可用 eventbus.WithMessageID(id) 显式指定
id, err = UserCreated.Publish(ctx, User{Name: "alice"},
	eventbus.WithMessageKey("alice"))

原始字节 / 原始信封:Topic.Publish 的 []byte 与 *RawEvent payload 按透传处理(跳过序列化、保留信封),或 app.Bus().Publish。 框架生命周期事件(lynx.*)始终走进程内内存 Transport。

完整演示:_examples/bus。设计说明:docs/design-eventbus.md。

Watermill Bus + Kafka

跨进程时用配置装配 Watermill Bus(bus: + kafka: 段)。总线依赖配置, 经 WithBusProvider 在框架装配好配置后构造(kafka 版装配入口 wmkafka.NewBusFromConfig)——不必在 NewRunner 之前自行读配置;返回的 Transport 由框架托管生命周期:

import (
	"github.com/lynx-go/lynx"
	wmkafka "github.com/lynx-go/lynx/contrib/watermill-kafka"
)

lynx.NewRunner(setup,
	lynx.WithName("my-app"),
	lynx.WithBusProvider(wmkafka.NewBusFromConfig),
).Run()
bus:
  max_redeliveries: 10   # 毒消息累计重投上限,超过后记 Error 并丢弃(默认 10)
  topics:
    user.created:
      route: { transport: kafka, key: user.created }
kafka:
  user.created:
    brokers: ["127.0.0.1:9092"]
    topics: [user_created]
    consumer: { group_id: users, instances: 3 }
    producer: { log_message: true }

Kafka record Key = Event.Key / MessageKey。Transport Subscribe 返回 Delivery(Ack / Nack),由 Bus 转达底层确认。

也可代码直接构造 Kafka Transport:

kafkaT, err := wmkafka.NewTransport(wmkafka.Options{
    Topics: map[string]wmkafka.TopicOptions{
        "user.created": {
            Brokers: []string{"127.0.0.1:9092"},
            Topics:  []string{"user_created"},
            Consumer: &wmkafka.ConsumerOptions{GroupID: "users", Instances: 3},
            Producer: &wmkafka.ProducerOptions{LogMessage: true},
        },
    },
})

Kafka 消费语义要点:

  • 同一事件多 handler 并行扇出:订阅单元是事件(逻辑 topic)——同一 逻辑 topic 上多个 handler 共享一条 transport 订阅并进程内并行触发, 每个 handler 都收到每条消息。消费组 / 消费者成员数是 kafka 配置 (kafka.<key>.consumer.group_id / .instances),多实例部署按该组 竞争消费。进程内在途上限由 bus.topics.<topic>.max_in_flight 控制 (默认 1,串行且保序;调大并发,goroutine 有界);挂死 handler 用 bus.handler_timeout 止损。不同逻辑 topic 路由到同一物理 topic 且组 相同时仍会互相瓜分,部署时应拆成不同 kafka 条目。
  • Transport 生命周期独立于 Bus:bus.Stop() 不关闭 opts.Transports / DefaultTransport;Kafka Transport 必须作为独立服务 Register 交由 框架托管 Start/Stop,漏注册则永远不会关闭。
  • log_message: true 输出的是 Debug 级日志,需 --log-level=debug (或 bus.debug: true)开启,并非 Info 级。
  • 毒消息止损:handler 终态失败(重试耗尽)后 Transport 会重投失败消息 (Kafka 默认 100ms 一轮);bus.max_redeliveries(默认 10,主题级 bus.topics.<topic>.max_redeliveries 可覆盖)限制同一条消息的累计 重投轮数,超过后记 Error 并丢弃该消息。
定时任务
import "github.com/lynx-go/lynx/contrib/schedule"

type MyTask struct{}

func (t *MyTask) Name() string { return "my-task" }
func (t *MyTask) Cron() string { return "0 */5 * * * *" } // 6 段,含秒
func (t *MyTask) HandlerFunc() schedule.HandlerFunc {
	return func(ctx context.Context) error { return nil }
}

scheduler, _ := schedule.NewScheduler([]schedule.Task{&MyTask{}})
app.Register(scheduler)

核心概念

Service
type Service interface {
	Name() string
	Init(ctx AppContext) error
	Start(ctx context.Context) error
	Stop(ctx context.Context) error
}

Init 接收 AppContext(Context / Config / Logger / HealthCheckers / Bus / Close),不依赖完整 App。Stop 与钩子错误由 Run() 聚合上抛。

Start 通常阻塞至关停(如 Serve);若只有非阻塞启动动作(拉起后台 goroutine、注册回调),用 lynx.WaitForShutdown(ctx) 收尾——Start 返回会立即触发整个应用关停。

注册须在 Run() 与 Close() 之前;Run() 开始后或 Close() 之后 Register / RegisterFactory 会 panic、Command 返回错误。

钩子与排水
app.OnPreStart(func(ctx context.Context) error { /* 服务启动前:迁移/预热 */ return nil })
app.OnPostStart(func(ctx context.Context) error { /* 所有服务 Start 已调用:运行通知 */ return nil })
app.OnDrain(func(ctx context.Context) error { /* 排水窗口:如从注册中心注销 */ return nil })
app.OnPreStop(func(ctx context.Context) error { /* 服务 Stop 前:最后冲刷 */ return nil })
app.OnPostStop(func() { /* 一切停止后:关闭 DB/Redis 连接池(Wire cleanup) */ })

WithDrainTimeout 开启排水窗口:就绪检查立即失败(lynx.ErrDraining),便于 LB 摘流;OnDrain 与排水睡眠并发执行,窗口即钩子总预算(DrainTimeout=0 时注册钩子会在启动期报 ErrDrainHooksRequireDrainTimeout);OnPostStop 收尾钩子受 WithCleanupTimeout(默认 10s)约束。

Wire
//go:generate wire
func InitializeApp() (*Bootstrap, error) {
	wire.Build(ProviderSet)
	return nil, nil
}

见 _examples/boot。

项目结构

lynx/
├── boot/                 # Bootstrap + Wire
├── eventbus/             # Bus / Topic / Event(默认内存)
├── client/{http,grpc}/   # 出站客户端
├── server/{http,grpc}/   # 入站服务器
├── debug/                # pprof(默认本机回环)
├── logging/              # slog 属性 / trace 注入
├── lynxtest/             # 测试套件(Run / NewContext / 拨号辅助)
├── internal/             # serverkit(server 共享规则)、clock(时间源)
├── contrib/
│   ├── watermill/        # Watermill 驱动的 eventbus.Bus
│   ├── watermill-kafka/  # Kafka Transport
│   ├── registry/         # Registrar / Resolver / memory / DNS
│   ├── consul/           # Consul 后端(含 cluster.Coordinator)
│   ├── registry-redis/   # Redis 注册发现后端(TTL 租约 + Pub/Sub)
│   ├── cluster/          # 进程间协调(Claim / Acquire / Singleton)
│   ├── cluster-redis/    # Redis cluster.Coordinator
│   ├── schedule/         # Cron
│   ├── telemetry/        # OpenTelemetry 生命周期
│   └── zap/              # Zap 日志
├── docs/                 # 文档与设计稿
└── _examples/            # boot / bus / bus-kafka / cli / http / registry / registry-redis / schedule

扩展模块

github.com/lynx-go/lynx/server/http
github.com/lynx-go/lynx/server/grpc
github.com/lynx-go/lynx/eventbus
github.com/lynx-go/lynx/contrib/watermill
github.com/lynx-go/lynx/contrib/watermill-kafka
github.com/lynx-go/lynx/contrib/telemetry
github.com/lynx-go/lynx/contrib/registry
github.com/lynx-go/lynx/contrib/consul
github.com/lynx-go/lynx/contrib/registry-redis
github.com/lynx-go/lynx/contrib/cluster
github.com/lynx-go/lynx/contrib/cluster-redis
github.com/lynx-go/lynx/contrib/schedule
github.com/lynx-go/lynx/contrib/zap

多模块发布时需分别打 tag(主仓 v{version},contrib 为 contrib/<name>/{version})。详见 RELEASE.md / mise run release-all -- vX.Y.Z "release vX.Y.Z"。

文档与示例

资源 说明
docs/01-introduction.md 项目简介
docs/02-quick-start.md 快速开始
docs/03-core-concepts.md 核心概念
docs/04-service-system.md 服务系统
docs/05-servers.md HTTP / gRPC
docs/06-clients.md 客户端
docs/07-registry.md 注册发现
docs/design-eventbus.md EventBus 设计
_examples/ 可运行示例

License

Apache License 2.0

欢迎提交 Issue 与 Pull Request。

Documentation

Overview

Package lynx 是 Lynx 微服务框架的核心包:提供应用生命周期管理、 服务系统、Hooks 机制、配置管理与 Context 辅助函数。

Index

Constants

View Source
const (
	DefaultName            = "lynx-app"
	DefaultShutdownTimeout = 5 * time.Second
	DefaultStopTimeout     = 5 * time.Second
	// DefaultBusReadyTimeout 是 newLynx 等待消息总线就绪的总预算(10 秒):
	// Watermill+Kafka 等后端的就绪明显慢于默认内存 Bus,1 秒级的硬编码
	// 预算会让正常部署下的构造直接失败,故放宽为可配的 10 秒。
	DefaultBusReadyTimeout = 10 * time.Second
	// DefaultCleanupTimeout 是 OnPostStop 收尾钩子的默认总预算(10 秒):
	// 对齐典型 Wire cleanup(关闭 DB/Redis 连接池)的合理上界,任何单个
	// Close 挂起都不阻塞进程退出。
	DefaultCleanupTimeout = 10 * time.Second
	// MinTimeout 与 MaxTimeout 是 ShutdownTimeout 与 StopTimeout 共用的
	// 校验区间(1 秒 ~ 5 分钟)。
	MinTimeout = 1 * time.Second
	MaxTimeout = 5 * time.Minute
)

Options 的默认值与校验区间。

Variables

View Source
var (
	// ErrNotInitialized 表示服务在 Init 之前被使用(如 Command 在未注册时直接 Start)。
	ErrNotInitialized = errors.New("service not initialized")
	// ErrSetupFuncNil 表示 NewRunner 未提供初始化回调。
	ErrSetupFuncNil = errors.New("setup func is nil")
	// ErrDrainHooksRequireDrainTimeout 表示注册了 OnDrain 钩子但未启用
	// 排水窗口(DrainTimeout=0)。v1.10.0 起排水窗口即 OnDrain 钩子的
	// 总预算(DrainHookTimeout 已并入 DrainTimeout):窗口未启用时钩子
	// 没有执行预算,注册即配置错误——Run() 启动期快失败,好过关停期
	// 静默跳过注销的延迟暴露。
	ErrDrainHooksRequireDrainTimeout = errors.New("on-drain hooks require DrainTimeout > 0 (set WithDrainTimeout); DrainTimeout=0 disables the entire drain phase")
	// ErrAppClosed 表示 Close 之后调用 Run。Close 在 Run 尚未被调度时
	// 到达(如测试的快速失败路径、宿主提前释放)即置位 closed:Run 入口
	// 直接返回本错误,不再执行任何钩子与服务——闭合"Run 从未启动时以
	// Close 释放"的契约,消除 Close 之后的僵尸生命周期。
	ErrAppClosed = errors.New("lynx: app has been closed")
)

Common errors that can be used throughout the framework.

View Source
var (
	// ErrNameTooLong 表示应用名超过 63 字符上限。
	ErrNameTooLong = errors.New("name must be at most 63 characters")
	// ErrShutdownTimeoutTooSmall 表示 ShutdownTimeout 非零但小于 MinTimeout。
	ErrShutdownTimeoutTooSmall = errors.New("shutdown timeout must be at least 1 second")
	// ErrShutdownTimeoutTooLarge 表示 ShutdownTimeout 大于 MaxTimeout。
	ErrShutdownTimeoutTooLarge = errors.New("shutdown timeout must be at most 5 minutes")
	// ErrStopTimeoutTooSmall 表示 StopTimeout 非零但小于 MinTimeout。
	ErrStopTimeoutTooSmall = errors.New("stop timeout must be at least 1 second")
	// ErrStopTimeoutTooLarge 表示 StopTimeout 大于 MaxTimeout。
	ErrStopTimeoutTooLarge = errors.New("stop timeout must be at most 5 minutes")
	// ErrDrainTimeoutInvalid 表示 DrainTimeout 为负值(排水窗口不允许负值)。
	ErrDrainTimeoutInvalid = errors.New("drain timeout must not be negative")
	// ErrBusReadyTimeoutInvalid 表示 BusReadyTimeout 为负值(就绪等待预算不允许负值)。
	ErrBusReadyTimeoutInvalid = errors.New("bus ready timeout must not be negative")
	// ErrCleanupTimeoutInvalid 表示 CleanupTimeout 为负值(收尾预算不允许负值)。
	ErrCleanupTimeoutInvalid = errors.New("cleanup timeout must not be negative")
)

Options 校验错误。

View Source
var ErrDraining = errors.New("draining")

ErrDraining 是排水窗口内 readiness 聚合返回的错误。排水置位后 drainChecker.CheckHealth 返回该错误,调用方可用 errors.Is 匹配 (例如 contrib 模块在排水边沿执行从服务目录注销)。

Functions

func BuildInfo added in v1.20.0

func BuildInfo() buildinfo.BuildInfo

BuildInfo 返回编译期注入的构建信息快照(与 Meta(ctx) 同款的取值函数 形态)。三元组本体与 ldflags -X 注入目标 vars 在 buildinfo 子包—— Go 不允许函数与类型同名,类型住进子包后根包的名字让给本函数。

func ContextWithMeta added in v1.15.0

func ContextWithMeta(parent context.Context, meta Metadata) context.Context

ContextWithMeta 返回携带应用元数据的 ctx(Meta 的对称写入口):框架在 init 时经此写入;lynxtest 与宿主嵌入场景可用同一入口构造带元数据的 上下文,使 lynx.Meta 可见。

func DefaultBindConfigFunc added in v0.6.0

func DefaultBindConfigFunc(f *pflag.FlagSet, c ConfigSource) error

DefaultBindConfigFunc 将默认 flags 中的配置文件路径、目录与类型绑定到应用配置源。

func DefaultBindFlagsFunc added in v1.4.0

func DefaultBindFlagsFunc(f *pflag.FlagSet)

DefaultBindFlagsFunc 绑定默认的命令行 flags:配置文件路径、类型、目录与日志级别。

func LogLevelFromConfig added in v1.0.0

func LogLevelFromConfig(c Config) string

LogLevelFromConfig 从配置中解析日志级别字符串。 契约:logging.level 是唯一规范键;log-level 与 log_level 是仅配置文件 的兼容回退(已废弃,不再有 flag 指向)。内置 --log-level 经 initConfigure 显式翻译成 Set("logging.level", …)——Set 为最高优先级,显式传参覆盖全部 配置键,未传时链按序回退。自定义命令行 flag / 配置 key 的唯一接入方式: 在 BindConfigFunc 里翻译进规范键(模式同内置翻译,见 _examples/boot)。 三个消费方共享本函数:applyLogLevel(框架默认路径)、contrib/zap 的 WithLoggerProvider 路径、lynxtest 的 TB logger——均未设置时返回空串, 由消费方自定缺省(info)。

func ParseLogLevel added in v1.0.0

func ParseLogLevel(s string) (slog.Level, error)

ParseLogLevel 解析日志级别字符串为 slog.Level。

func Set added in v1.5.1

func Set(ctx AppContext)

Set 设置进程默认 AppContext(类比 slog.SetDefault / eventbus.SetDefault)。 newLynx 成功后调用。

单 App 进程假设:该全局槽只有一个,多 App 并存(典型是测试)时后设置 者覆盖前者。测试清理模式:用例结束后 Set(nil) 复位,避免泄漏到同进程 的后续用例(与 eventbus.SetDefault 的清理模式一致)。

func WaitForShutdown added in v1.16.0

func WaitForShutdown(ctx context.Context) error

WaitForShutdown 阻塞至 ctx 取消后返回 nil,作为 Service.Start 的阻塞收尾: 当 Start 的实际工作直接返回(只拉起后台 goroutine、注册回调、启动定时器 等)时,直接返回会触发应用立即关停;在启动动作完成后调用本方法保持服务 actor 存活,直至框架关停取消服务 ctx:

func (s *myService) Start(ctx context.Context) error {
	go s.loop(ctx)
	return lynx.WaitForShutdown(ctx)
}

阻塞式服务(http.Server.Serve、自身的消费循环等)直接调用即可,不需要 本方法;本方法只等待关停,不做任何清理——资源释放放在 Stop。

Types

type App

type App interface {
	AppContext
	// Command 注册启动的命令,用于 CLI 模式。选项经 opts 传入
	// (WithMaxTries / WithBackoff / WithProbeTimeout / WithCommandName)。
	Command(cmd CommandFunc, opts ...CommandOption) error

	// OnPreStart 注册应用启动阶段执行的钩子函数:先于所有服务启动
	// 顺序执行,首个错误中止启动(已 Init 的服务逆序停止)。
	OnPreStart(fns ...HookFunc)
	// OnDrain 注册排水阶段执行的钩子函数:关停时 drainChecker 置位后
	// 与 DrainTimeout 窗口睡眠并发执行(如从服务目录注销),窗口即
	// 钩子总预算——窗口结束(无论钩子是否完成)即继续后续关停。
	// 必须启用排水(WithDrainTimeout,> 0):DrainTimeout=0 时整段
	// 禁用,此时注册钩子由 Run() 返回 ErrDrainHooksRequireDrainTimeout。
	// 除手动注册外,实现 Drainer 接口的服务在 Register 登记时由框架
	// 自动挂载排水钩子(见 service.go),应用侧无需重复挂钩。
	OnDrain(fns ...HookFunc)
	// OnPreStop 注册应用停止阶段执行的钩子函数:先于服务 Stop 执行
	// (此时服务仍在服务在途请求,适合"停止接收前的最后冲刷",不适合
	// 释放在途请求还要用的底层资源——那类资源放 OnPostStop)。服务进入
	// 运行阶段后,所有退出路径(信号/Close/服务失败/钩子失败/命令完成)
	// 都保证此顺序;Init/OnPreStart 失败路径不执行本阶段。
	OnPreStop(fns ...HookFunc)
	// OnPostStart 注册服务启动后执行的"运行通知"钩子:所有服务 actor
	// 进入执行体(Start 调用紧随其后,可能与钩子的最初几条指令并发)、
	// run group 进入运行态后顺序执行。阻塞型服务(HTTP/gRPC server)
	// 的 Start 直到关停才返回,故不存在"所有 Start 已返回"的时刻——
	// 钩子触发不代表端口已监听或就绪(就绪语义用健康检查表达)。钩子
	// 错误视为启动失败,触发整个应用的关停并随 Run() 上抛。
	OnPostStart(fns ...HookFunc)
	// OnPostStop 注册进程收尾清理钩子:所有服务 Stop、总线关停之后、
	// Run 返回前逆序执行(LIFO,与 defer/Wire cleanup 语义一致),总预算
	// CleanupTimeout(默认 10 秒),超时记日志并跳过剩余钩子,不阻塞
	// 进程退出。用于释放 DI 底层资源(DB/Redis 连接池等)。签名是无
	// 错误返回的 CleanupFunc:终局阶段错误没有消费者。Run 的所有退出
	// 路径(含服务 Init 失败、PreStart 失败)都会执行;Run 从未调用时
	// 由 Close() 兜底。
	OnPostStop(fns ...CleanupFunc)
	// Register 注册需要由应用托管生命周期的服务实例。
	// 服务的 Init 在注册时同步执行;注册阶段产生的错误不会立即返回,
	// 首个错误会被记录,并在 Run() 时统一返回。
	// 所有注册必须先于 Run 与 Close:Run 开始后或 Close 之后调用将 panic。
	Register(services ...Service)
	// RegisterFactory 注册需要由应用托管生命周期的服务工厂,
	// 错误处理语义与 Register 相同;同样必须先于 Run 与 Close。
	RegisterFactory(factories ...ServiceFactory)

	// Run 运行应用主流程:执行 on-pre-start 钩子、启动所有服务并等待退出信号。
	// Run 开始后或 Close 之后,Register/RegisterFactory 为禁止操作(panic),
	// Command 返回错误。
	Run() error
}

App 是应用实例的核心接口:在 AppContext 的基础上增加服务注册、 生命周期钩子与运行控制能力。

钩子阶段按触发顺序(Pre/Post 锚定"服务组"的启停):

OnPreStart  服务启动前,顺序执行,首错中止启动
OnPostStart 所有服务的 Start 已被调用后(阻塞型服务以进入 Start 为界)
OnDrain     关停发起、readiness 已摘流后,与排水窗口并发
OnPreStop   服务 Stop 之前(服务仍在服务在途请求)
OnPostStop  所有服务与总线停止之后、Run 返回前(进程收尾清理)

func NewApp added in v1.12.0

func NewApp(opts ...Option) (App, error)

NewApp 按选项构造 Lynx 应用并返回 App 实例,不经 Runner 包装: 适用于测试(配合 lynxtest)与把 Lynx 嵌入宿主进程的场景。构造语义与 NewRunner 严格一致(opts 应用在空 Options 上,再由 newLynx 做 EnsureDefaults/Validate、配置装配、总线提前 Start 与就绪等待——顺序 敏感的 Option 如 WithBusOptions 依赖 Bus 尚未填充默认值的空 Options), 初始化错误经返回值给出。调用方随后 Register 组装服务并 Run;Run 从未 启动时以 Close 释放(停止总线并兜底 post-stop 钩子)。

type AppContext added in v1.0.0

type AppContext interface {
	// Context 获取应用上下文
	Context() context.Context
	// Config 获取配置实例(默认由 *viper.Viper 适配实现)
	Config() Config
	// Logger 获取 logger
	Logger(kwargs ...any) *slog.Logger
	// Bus 获取应用级消息总线(一等对象,开箱即为内存实现,可被 Watermill/Kafka 装饰)。
	Bus() eventbus.Bus
	// HealthCheckers 返回当前已注册的健康检查器快照(注册时收集)。
	HealthCheckers() []Checker
	// Close 关闭应用实例(如一次性命令执行完毕)。
	Close()
}

AppContext 是框架提供给服务的应用上下文:服务的 Init 只依赖 AppContext, 不依赖完整的 App(App 是 AppContext 的超集)。服务因此不需要为测试实现 App 的其余方法。

func Get added in v1.5.1

func Get() AppContext

Get 返回 Set 设置的 AppContext;未设置时返回 nil。 单 App 进程假设同 Set:返回的是最近一次 Set 的实例,多 App 测试场景 下不保证属于当前用例——需要确定归属时优先经由依赖注入传递 App, 而非依赖本全局槽。

type BindConfigFunc added in v0.6.0

type BindConfigFunc func(f *pflag.FlagSet, c ConfigSource) error

BindConfigFunc 将命令行 flags 绑定到应用配置源(ConfigSource 实例)。

type BindFlagsFunc added in v1.4.0

type BindFlagsFunc func(f *pflag.FlagSet)

BindFlagsFunc 定义应用启动时需要绑定的命令行 flags。

type Checker added in v1.0.0

type Checker interface {
	CheckHealth() error
}

Checker 是健康检查接口:返回 nil 表示健康,返回非 nil 表示不健康。 替代 gocloud.dev/server/health.Checker,消除对该模块的依赖。

type CleanupFunc added in v1.10.0

type CleanupFunc func()

CleanupFunc 是进程收尾清理回调,签名为 func():终局阶段(一切已停止) 错误没有消费者,实现方自行记日志。与 Wire 生成的 cleanup 函数签名 原生对齐,app.OnPostStop(cleanup) 零适配。

type Clock added in v1.15.0

type Clock interface {
	Now() time.Time
	// After 在 d 之后向返回的 channel 发送当前时间(语义同 time.After)。
	After(d time.Duration) <-chan time.Time
}

Clock 是框架模块的时间源接缝:生产使用 internal/clock.Real(),测试可 注入可控时钟(internal/clock.Fake)以确定性断言 TTL / 过期 / stale 边界, 而不是 sleep 真实时间。消费方:contrib/cluster 的租约续约与内存协调器、 contrib/registry 的缓存 stale 判定。

type CommandFunc added in v0.6.0

type CommandFunc func(ctx context.Context) error

CommandFunc 是命令服务执行的业务函数,返回错误时视为命令失败。

type CommandOption added in v0.0.6

type CommandOption func(*CommandOptions)

CommandOption is a function that configures CommandOptions.

func WithBackoff added in v0.7.1

func WithBackoff(initial, max time.Duration) CommandOption

WithBackoff sets the initial and maximum backoff durations.

func WithCommandName added in v1.0.0

func WithCommandName(name string) CommandOption

WithCommandName sets the command service name used in logs.

func WithMaxTries added in v0.7.1

func WithMaxTries(n uint) CommandOption

WithMaxTries sets the maximum number of retry attempts.

func WithProbeTimeout added in v1.13.0

func WithProbeTimeout(d time.Duration) CommandOption

WithProbeTimeout sets the upper bound for a single dependency probe (health check or ready-signal wait). Non-positive values fall back to the 3s default.

func WithWaitBudget added in v1.16.0

func WithWaitBudget(d time.Duration) CommandOption

WithWaitBudget sets the wall-clock budget for the whole dependency wait (Wait budget semantics): non-positive values mean unlimited (default), where only the attempts/backoff round budget applies. When set, the total wait is capped and whichever budget is reached first wins.

type CommandOptions added in v0.7.1

type CommandOptions struct {
	Name           string
	MaxTries       uint
	InitialBackoff time.Duration
	MaxBackoff     time.Duration
	// ProbeTimeout bounds a single dependency probe (one CheckHealth
	// call or one Ready-channel wait). A probe that exceeds it counts
	// as "not ready this round" and joins the backoff retry loop.
	ProbeTimeout time.Duration
	// WaitBudget is the wall-clock budget for the whole dependency wait.
	// 0 (default) means unlimited: only the attempts/backoff round budget
	// applies. Non-zero caps the total wait; whichever budget is reached
	// first wins (Wait budget semantics).
	WaitBudget time.Duration
}

CommandOptions configures the command service behavior.

type Config added in v1.0.0

type Config interface {
	// Get 返回 path 对应的值,未设置时返回 nil。
	Get(path string) any
	// GetString 返回 path 对应的字符串值。
	GetString(path string) string
	// GetBool 返回 path 对应的布尔值。
	GetBool(path string) bool
	// GetInt 返回 path 对应的整数值。
	GetInt(path string) int
	// GetStringMap 返回 path 对应的键值映射。
	GetStringMap(path string) map[string]any
	// GetStringSlice 返回 path 对应的字符串切片。
	GetStringSlice(path string) []string
	// IsSet 报告 path 是否已设置。
	IsSet(path string) bool
	// Unmarshal 将配置解码到 out 指向的结构体。结构体目标默认走结构体驱动的
	// 逐叶取值:tag 回退链 mapstructure → json → 小写字段名,仅在环境变量
	// 设置的键(配置文件无此键)也参与解码;非结构体目标(map 等,无法
	// 枚举叶子)回落 viper 语义。通过 opts 选择或定制解码行为(见 UnmarshalOption)。
	Unmarshal(out any, opts ...UnmarshalOption) error
	// UnmarshalKey 将 path 对应的配置子树解码到 out 指向的结构体;
	// opts 语义与 Unmarshal 相同,叶子键以 path 为前缀。
	UnmarshalKey(path string, out any, opts ...UnmarshalOption) error
}

Config 是应用配置的通用读取接口,与具体配置库解耦。 默认实现适配 *viper.Viper(见 NewViperConfig)。 path 使用点分路径(如 "logging.level"),具体语义由实现定义。

type ConfigSource added in v1.0.0

type ConfigSource interface {
	Config
	// Set 设置 path 的值。
	Set(path string, value any)
	// SetFile 设置配置文件路径。
	SetFile(path string)
	// AddSearchPath 添加配置文件搜索目录。
	AddSearchPath(dir string)
	// SetFileFormat 设置配置文件格式(如 yaml、json)。
	SetFileFormat(format string)
	// SetEnvPrefix 设置环境变量前缀。
	SetEnvPrefix(prefix string)
	// SetEnvKeyReplacer 设置环境变量键名替换规则,用于把点分路径键映射为
	// 环境变量名(如 "." → "_"),使任意键都能被环境变量覆盖。
	SetEnvKeyReplacer(repl *strings.Replacer)
	// AutomaticEnv 启用环境变量自动匹配。
	AutomaticEnv()
	// BindEnv 将 path 绑定到环境变量;env 为空时使用 path 的默认环境变量形式。
	BindEnv(path string, env ...string) error
}

ConfigSource 是配置源的绑定接口,在初始化绑定阶段(BindConfigFunc) 使用,在 Config 的基础上增加写入与配置源管理方法。 默认实现同样适配 *viper.Viper。

func NewViperConfig added in v1.0.0

func NewViperConfig(v *viper.Viper) ConfigSource

NewViperConfig 将 *viper.Viper 包装为 ConfigSource(同时也是 Config), 是框架的默认实现。其他配置库可自行实现 Config / ConfigSource 接入。

type Drainer added in v1.18.0

type Drainer interface {
	DrainHook() HookFunc
}

Drainer 是可选接口:服务在关停排水边沿要执行的动作(如 Registrar 在 LB 摘流阶段从服务目录注销)。Register 登记时框架调用 DrainHook 取钩子 并挂入排水阶段——与 app.OnDrain 同列、按服务注册顺序执行、共享 DrainTimeout 窗口预算。服务因此不需要 App 句柄:注册即接入,不存在 忘记挂钩子的第二条路径。

返回 nil 表示该服务不参与排水(如依赖后端 TTL 过期的服务以选项关闭), 框架跳过挂载,也不计入「启用排水须设置 WithDrainTimeout」的启动期 快失败。DrainHook 在登记路径被调用一次(Init 成功之后、app.mu 之外), 必须是纯取值:不得阻塞、加锁或访问网络;返回的钩子在关停时才执行。

type EventHandler added in v1.16.0

type EventHandler[T any] interface {
	// Topic 返回订阅的类型化主题。
	Topic() eventbus.Topic[T]

	// HandlerName 是 Bus 内全局唯一的 handler 名,同时用作服务名
	//(启动/停止日志中的标识)。空名在 Init 期报错。
	HandlerName() string

	// Init 是依赖注入点:EventHandlerService 保证它在订阅之前调用,可用
	// AppContext 获取构造期不可得的依赖(配置、日志等);无依赖时返回 nil。
	// 返回错误则不订阅,由 app.Run() 统一上抛。
	Init(ctx AppContext) error

	// Handle 处理一条已解码的事件。返回错误时按订阅选项重试或确认
	//(重试 / AutoAck / ContinueOnError 语义由 Bus 与 SubscribeOption 决定)。
	Handle(ctx context.Context, event *eventbus.Event[T]) error
}

EventHandler 是业务侧对「一个类型化订阅」的完整声明:主题、handler 名、 依赖注入点与处理函数。业务结构体直接实现本接口,经 NewEventHandlerService 适配为 Service 后 app.Register——不需要嵌入骨架,也不需要构造后回填。

type OrderCreatedHandler struct {
	name string
	db   *sql.DB
}

func (h *OrderCreatedHandler) Topic() eventbus.Topic[OrderCreated] { return OrderCreatedTopic }
func (h *OrderCreatedHandler) HandlerName() string                { return h.name }
func (h *OrderCreatedHandler) Init(ctx lynx.AppContext) error     { return nil }
func (h *OrderCreatedHandler) Handle(ctx context.Context, e *eventbus.Event[OrderCreated]) error {
	return h.db.Do(ctx, e.Payload)
}

app.Register(lynx.NewEventHandlerService(&OrderCreatedHandler{name: "order-created", db: db}))

type EventHandlerService added in v1.17.0

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

EventHandlerService 把 EventHandler 适配为 Service:

  • Name:即 HandlerName,构造后立即可用(框架可能在 Init 前调用);
  • Init:先调用 h.Init 注入依赖,再订阅 Topic(依赖未就绪不会先消费);
  • Start:订阅已在 Init 完成,无自有循环,阻塞至关停(WaitForShutdown);
  • Stop:无资源可释放。

对比嵌入式骨架:适配器持有已构造好的 handler,所有方法静态可用, 不存在「基类回调派生类方法」的两阶段初始化与 nil 接口窗口。

func NewEventHandlerService added in v1.17.0

func NewEventHandlerService[T any](h EventHandler[T], opts ...eventbus.SubscribeOption) *EventHandlerService[T]

NewEventHandlerService 创建 handler 服务。opts 透传给 Topic.Subscribe, 只影响该 handler 自身的投递语义(WithSubscribeRetry / WithAutoAck / WithContinueOnError);默认以 HandlerName 作为 Bus 内 handler 名, 显式 eventbus.WithHandlerName 可覆盖。

同一事件的多个 handler 服务共享该事件的一条 transport 订阅并进程内 并行扇出:消费组 / 消费者成员数是后端配置(kafka consumer.group_id / instances),订阅级在途上限是事件配置(WithTopicMaxInFlight / Options.Topics.max_in_flight)。

func (*EventHandlerService[T]) Init added in v1.17.0

func (s *EventHandlerService[T]) Init(ctx AppContext) error

Init 注入依赖后订阅主题。顺序保证:h.Init 返回 nil 才会订阅。

func (*EventHandlerService[T]) Name added in v1.17.0

func (s *EventHandlerService[T]) Name() string

Name 返回服务名(即 handler 名)。不依赖 Init,注册前调用安全; 未配置(nil 服务 / nil handler)时返回空串而非 panic。

func (*EventHandlerService[T]) Start added in v1.17.0

func (s *EventHandlerService[T]) Start(ctx context.Context) error

Start 订阅已在 Init 完成,无自有循环:阻塞至关停。

func (*EventHandlerService[T]) Stop added in v1.17.0

Stop 无资源可释放。

type FactoryOptions added in v1.0.0

type FactoryOptions struct {
	Instances int `json:"instances"` // 实例数
}

FactoryOptions 描述服务构建参数。

type HealthChecker added in v0.6.0

type HealthChecker struct {
	// contains filtered or unexported fields
}

HealthChecker 是基于布尔状态的健康检查器,可并发使用。

func (*HealthChecker) CheckHealth added in v0.6.0

func (check *HealthChecker) CheckHealth() error

CheckHealth 实现 Checker 接口,当前状态不健康时返回错误。

func (*HealthChecker) SetHealthy added in v0.6.0

func (check *HealthChecker) SetHealthy(healthy bool)

SetHealthy 设置当前健康状态。

type HealthCheckersFunc added in v1.0.0

type HealthCheckersFunc func() []Checker

HealthCheckersFunc 是健康检查器的取值函数,用于 server 类服务的健康检查 配置。方法值 app.HealthCheckers 天然匹配该签名。

type HookFunc added in v0.6.0

type HookFunc func(ctx context.Context) error

HookFunc 是应用生命周期钩子函数,返回错误时视为钩子执行失败。

type Lifecycle added in v1.0.0

type Lifecycle interface {
	Init(ctx AppContext) error
	Start(ctx context.Context) error
	Stop(ctx context.Context) error
}

Lifecycle 定义服务的生命周期管理接口:初始化、启动与停止。 Stop 的调用契约:必须容忍在 Start 之前被调用——Init 成功但 Start 未执行(或 Start 已失败)时,框架会逆序调用 Stop 做资源清理。 实现不得假设 Start 必然先于 Stop。Stop 返回的错误会被框架收集, 与 OnPreStop 钩子错误一起由 Run() 统一上抛给调用方。

type Metadata added in v1.3.0

type Metadata struct {
	// Name is the application name.
	Name string
	// ID is the instance ID (hostname by default).
	ID string
	// Version is the application version.
	Version string
}

Metadata describes the application metadata carried in the context: name, instance ID and version.

func Meta added in v0.0.10

func Meta(ctx context.Context) Metadata

Meta returns the application metadata from the context. Fields are empty strings if not set or of wrong type.

type Option

type Option func(*Options)

Option 用于配置 Options 的选项函数。

func WithBindConfigFunc added in v0.6.0

func WithBindConfigFunc(f BindConfigFunc) Option

WithBindConfigFunc 设置自定义的配置绑定函数。

func WithBindFlagsFunc added in v1.4.0

func WithBindFlagsFunc(f BindFlagsFunc) Option

WithBindFlagsFunc 设置自定义的命令行 flags 绑定函数。

func WithBus added in v1.5.0

func WithBus(b eventbus.Bus) Option

WithBus 注入自定义消息总线;nil 时框架使用内存默认总线(开箱即用)。

func WithBusOptions added in v1.5.0

func WithBusOptions(opts ...eventbus.Option) Option

WithBusOptions 以选项配置默认内存总线(Bus 为 nil 时生效;已注入 Bus 时无视)。 BusProvider 已设置时同样无视:配置驱动的总线由 provider 构造,内存总线 选项无意义。若本选项先于 WithBusProvider 应用(此时物化了内存总线), provider 仍会覆盖物化结果——两个选项对顺序不敏感,provider 不会被静默击败。

func WithBusProvider added in v1.12.0

func WithBusProvider(fn func(cfg Config) (eventbus.Bus, []Service, error)) Option

WithBusProvider 设置配置驱动的总线构造器:框架在构造序列内、配置装配 完成后以装配好的 Config 调用,用于依赖配置的总线(如 watermill.NewFromConfig——此前这类总线必须在 NewRunner 之前自行读取 配置再经 WithBus 注入)。返回的服务(如 kafka Transport)按 Register 语义托管:Init 同步执行、Start/Stop 纳入生命周期、实现 Checker 的进入 健康聚合(CLI 命令的健康等待因此能等 Transport 就绪)。 与 WithBus 并存时 WithBus 优先(provider 仅在 Bus 为 nil 时被咨询); provider 返回 nil 总线视为构造错误。

func WithBusReadyTimeout added in v1.6.0

func WithBusReadyTimeout(timeout time.Duration) Option

WithBusReadyTimeout 设置 newLynx 等待消息总线就绪的总预算(默认 10 秒)。 Watermill+Kafka 等后端的就绪明显慢于内存 Bus,可按部署环境调宽; 0 表示回退默认值(无法显式禁用),负值会在 Validate 时报错。

func WithCleanupTimeout added in v1.10.0

func WithCleanupTimeout(timeout time.Duration) Option

WithCleanupTimeout 设置 OnPostStop 收尾钩子的总预算(默认 10 秒): 所有服务与总线停止之后、Run 返回前,逆序执行收尾钩子(如 Wire cleanup 关闭 DB/Redis 连接池)。超时记日志并跳过剩余钩子,不阻塞 进程退出。与 ShutdownTimeout 是独立预算。0 表示回退默认值, 负值会在 Validate 时报错。

func WithConfig added in v1.12.0

func WithConfig(c Config) Option

WithConfig 注入现成的应用配置:构造期跳过 flags 解析、配置文件搜索与 BindPFlags(BindFlagsFunc/BindConfigFunc 不再执行),os.Args 与工作目录 不再参与装配。init 仍从该配置读取 service.name/id/version 元数据并应用 logging.level 日志级别。nil 传入无效(保持默认装配路径)。 典型用于测试(配合 lynxtest)与宿主进程内嵌场景。

func WithConfigFile added in v1.12.0

func WithConfigFile(path string) Option

WithConfigFile 设置配置文件路径并关闭默认的命令行 flags,用于参数由 外部解析的场景(典型如子命令框架已解析 -c/--config):路径直接绑定为 配置文件,path 为空时回退搜索工作目录(与 DefaultBindConfigFunc 的 回退一致)。 等价于按序应用 WithDisableConfigFlags 与 WithBindConfigFunc——顺序敏感 (前者会清空 BindConfigFunc),封装为单一选项消除该陷阱。与其他选项 同用时遵循 Option 后到者胜的通用语义。 测试场景的配置注入(分层叠加、构造期即时读入)见 lynxtest 包的 WithConfigBaseline 系列选项。

func WithConfigWatch added in v1.13.0

func WithConfigWatch() Option

WithConfigWatch 启用配置文件热更新(viper WatchConfig):文件变更时 框架发布 lynx.config.updated 事件(eventbus.ConfigUpdatedTopic, 订阅示例见该 Topic 注释),此后 Config() 读取返回新值——订阅方收到 事件后重新读取配置并自行决定响应粒度(重建连接/调参/忽略)。 仅对文件来源的配置生效(--config / -c 或 WithConfigFile):无配置 文件时 Run() 启动期返回错误(显式要求热更新却无从 watch,快失败 好过静默失效)。WithConfig 注入自定义 Config 实现的场景同样报错 (无 viper 文件句柄可 watch)。

func WithDisableConfigFlags added in v1.0.0

func WithDisableConfigFlags() Option

WithDisableConfigFlags 关闭默认的命令行 flags 与配置绑定。 默认行为:未显式设置 BindFlagsFunc/BindConfigFunc 时,框架自动启用内置的 参数声明与绑定(见 DefaultBindFlagsFunc/DefaultBindConfigFunc)。

func WithDrainTimeout added in v1.1.0

func WithDrainTimeout(timeout time.Duration) Option

WithDrainTimeout 设置关停排水(drain)窗口时长:关停信号到达后先让 readiness 失败(LB 摘流),等待该窗口结束后才真正关停。窗口同时是 OnDrain 钩子的总预算(钩子与窗口睡眠并发执行,窗口结束即继续关停)。 0(默认)表示不启用排水——整段(窗口与钩子)禁用;此时注册了 OnDrain 钩子会在 Run() 启动期返回 ErrDrainHooksRequireDrainTimeout。 与 ShutdownTimeout 是独立预算:总关停时长上界 = DrainTimeout + ShutdownTimeout + 各服务 StopTimeout 叠加 + CleanupTimeout。 取值任意 ≥0,无下限约束。

func WithExitSignals added in v0.6.0

func WithExitSignals(signals ...os.Signal) Option

WithExitSignals 设置触发应用退出的操作系统信号。

func WithID

func WithID(id string) Option

WithID 设置应用实例 ID。

func WithIsolated added in v1.12.0

func WithIsolated() Option

WithIsolated 使应用不触碰进程级全局状态:构造时不执行 eventbus.SetDefault 与 lynx.Set,logger provider 与日志级别应用不再同步 slog.SetDefault。用于同一 进程内构造多个 App(表驱动/并行测试、宿主内嵌)互不污染全局。 代价:依赖全局取值的代码(eventbus.Default()、lynx.Get()、裸 slog 调用) 看不到该实例,需要改用注入的 AppContext/Bus。默认关闭。

func WithLoggerProvider added in v1.16.0

func WithLoggerProvider(fn func(ctx AppContext) (*slog.Logger, error)) Option

WithLoggerProvider 设置依赖配置的 logger 构造器:框架在构造序列内、 配置装配与元数据解析完成后以 AppContext 调用——provider 可读 Config()(如 logging.level)与 Context() 里的 Meta,用于依赖配置的 logger(如 contrib/zap 的 NewLogger,签名直接匹配可直接传入)。 此前这类 logger 只能在 SetupFunc 里经 App.SetLogger 事后注入,晚于 总线及其配套服务的 logger 捕获(bus/router/transport 构造期捕获 slog.Default() 后即冻结),导致装配期日志格式与运行期不一致; provider 路径下总线构造前 logger 即已就位,从结构上消除该分裂。 产出的 logger 即 app.logger 并同步 slog.SetDefault(WithIsolated 时不触碰全局);返回 nil logger 或错误均使构造失败(快失败)。 配置 provider 后视为用户定制:框架跳过 logging.level 的默认 TextHandler 重建(级别归 provider 装配逻辑,键链契约见 lynx.LogLevelFromConfig——自定义 flag/key 须翻译进规范键),SetLogLevel 不再代理级别调整(debug /loglevel 端点返回 501)。

func WithName

func WithName(name string) Option

WithName 设置应用名称。

func WithShutdownTimeout added in v0.7.2

func WithShutdownTimeout(timeout time.Duration) Option

WithShutdownTimeout 设置应用优雅关停的超时时间。 注意:0 不是"禁用上界",会被 EnsureDefaults 折叠为默认值(5 秒), 显式禁用上界当前无法表达(与 server 侧 ShutdownTimeout=0 的 "无上界"语义不一致,历史行为冻结不改)。

func WithStopTimeout added in v1.0.0

func WithStopTimeout(timeout time.Duration) Option

WithStopTimeout 设置单个服务 Stop 的最长等待时长,超过后跳过并记录错误。 注意:0 不是"禁用上界",会被 EnsureDefaults 折叠为默认值(5 秒), 显式禁用上界当前无法表达(与 server 侧 ShutdownTimeout=0 的 "无上界"语义不一致,历史行为冻结不改)。

func WithVersion

func WithVersion(v string) Option

WithVersion 设置应用版本号。缺省解析链的兜底顺序:配置键 service.version → 本选项 → 编译期注入的 buildinfo.Version(见 buildinfo 子包)——构建脚本注入后应用可不传本选项。

type Options added in v0.6.0

type Options struct {
	ID             string         `json:"id"`
	Name           string         `json:"name"`
	Version        string         `json:"version"`
	BindFlagsFunc  BindFlagsFunc  `json:"-"`
	BindConfigFunc BindConfigFunc `json:"-"`
	ExitSignals    []os.Signal    `json:"-"`
	Bus            eventbus.Bus   `json:"-"`
	// BusProvider 非 nil 且 WithBus 未注入时,在配置装配完成后由框架调用
	// 以构造应用总线(依赖配置的总线如 watermill.NewFromConfig)及其配套
	// 服务(如 kafka Transport)。与 WithBus 并存时 WithBus 优先。
	BusProvider func(cfg Config) (eventbus.Bus, []Service, error) `json:"-"`
	// LoggerProvider 非 nil 时,在配置装配与元数据解析完成后、总线构造前
	// 由框架调用,产出应用 logger(依赖配置与 meta 的 logger,如
	// contrib/zap 的 NewLogger)。配置了 provider 时框架跳过 logging.level
	// 的默认 TextHandler 重建(applyLogLevel)——级别归 provider 自己的
	// 装配逻辑(zap 侧从 ctx.Config() 读取)。
	LoggerProvider func(ctx AppContext) (*slog.Logger, error) `json:"-"`
	// ConfigWatch 启用配置文件热更新(WithConfigWatch):Run 启动期注册
	// viper WatchConfig,文件变更时框架经总线发布 lynx.config.updated
	// 事件(eventbus.ConfigUpdatedTopic),后续 Config() 读取返回新值;
	// 订阅方自行决定响应粒度。要求配置来自文件,否则 Run 启动期报错。
	ConfigWatch bool `json:"-"`

	ShutdownTimeout time.Duration `json:"shutdown_timeout"`
	// StopTimeout 是单个服务 Stop 的最长等待时长,超过后跳过并记录错误,
	// 防止挂死的服务阻塞整个关停流程。
	// ShutdownTimeout 与 StopTimeout 的 0 均表示"未设置":EnsureDefaults
	// 会折叠为默认值,无法显式表达"禁用上界"(注意与 server 侧
	// ShutdownTimeout=0 的"无上界"语义不同)。
	StopTimeout time.Duration `json:"stop_timeout"`
	// DrainTimeout 是关停排水(drain)窗口时长,v1.10.0 起同时是
	// OnDrain 钩子的总预算(DrainHookTimeout 已并入):关停时先让
	// readiness 失败(LB 摘流),OnDrain 钩子(如从服务目录注销)与
	// 窗口睡眠并发执行,窗口结束时无论钩子是否完成都继续后续关停。
	// 0(默认)表示不启用排水——整段(窗口与钩子)禁用;此时注册了
	// OnDrain 钩子会在 Run() 启动期返回 ErrDrainHooksRequireDrainTimeout。
	// 与 ShutdownTimeout 是独立预算:总关停时长上界 =
	// DrainTimeout + ShutdownTimeout + 各服务 StopTimeout 叠加 + CleanupTimeout。
	// 取值任意 ≥0,无下限约束(1ms 等小值合法)。
	DrainTimeout time.Duration `json:"drain_timeout"`
	// BusReadyTimeout 是 newLynx 构造应用时等待消息总线就绪
	// (CheckHealth 通过)的总预算,默认 10 秒:Watermill+Kafka 等
	// 慢启动后端需要比 1 秒级硬编码更宽的就绪窗口。0 表示使用默认值
	//(无法显式禁用等待——总线就绪是构造成功的硬前提);负值在
	// Validate 时报错。
	BusReadyTimeout time.Duration `json:"bus_ready_timeout"`
	// CleanupTimeout 是 OnPostStop 收尾钩子的总预算(默认 10 秒):
	// 所有服务与总线停止之后、Run 返回前,逆序执行收尾钩子(关闭
	// DB/Redis 连接池等 DI 底层资源)。与 ShutdownTimeout 是独立预算:
	// 总关停时长上界 = 排水段 + ShutdownTimeout + 各服务 StopTimeout
	// 叠加 + CleanupTimeout。0 表示使用默认值;负值在 Validate 时报错。
	CleanupTimeout time.Duration `json:"cleanup_timeout"`

	// Config 非 nil 时作为应用配置直接采用(WithConfig 注入):构造期跳过
	// flags 解析与配置文件装配(BindFlagsFunc/BindConfigFunc 不再执行),
	// os.Args 与工作目录不参与配置。用于测试与宿主进程注入。
	Config Config `json:"-"`
	// contains filtered or unexported fields
}

Options 是 App 应用的核心配置项。

func NewOptions added in v0.6.0

func NewOptions(opts ...Option) *Options

NewOptions 创建带默认值的 Options,并按顺序应用给定的选项。

func (*Options) EnsureDefaults added in v0.6.0

func (o *Options) EnsureDefaults()

EnsureDefaults sets default values for unset fields. 校验由 Validate 单独负责,newLynx 会在 EnsureDefaults 后调用它。

func (*Options) String added in v0.6.0

func (o *Options) String() string

String 返回 Options 的 JSON 字符串表示(函数类字段不参与序列化)。

func (*Options) Validate added in v0.7.1

func (o *Options) Validate() error

Validate checks if the Options values are valid.

type OrderedOption added in v1.16.0

type OrderedOption func(*orderedServices)

OrderedOption 配置 OrderedServices 组行为。

func WithOrderedReadyTimeout added in v1.16.0

func WithOrderedReadyTimeout(d time.Duration) OrderedOption

WithOrderedReadyTimeout 覆盖每子服务的就绪等待预算(默认 defaultOrderedReadyTimeout = 10s;嵌套组逐层按各自子服务分别计时)。 非正值使用默认值。

type Ready added in v1.6.0

type Ready interface {
	Ready() <-chan struct{}
}

Ready 是可选接口:服务在进入可工作状态时关闭返回的 channel (例如 Listen 成功之后、Serve 之前)。 OrderedServices 与 command 服务的依赖等待在检测到该接口时优先采用: 前者在启动下一个子服务前等待其关闭;后者(三级优先 Ready → Checker 轮询 → 无信号即就绪)以此为命令起跑的边沿信号。 未实现则回退到 Checker 轮询,再否则视为已 invoke 即就绪。 仅在成功跨过启动门槛后关闭;Listen/Start 失败不得关闭,以便等待方 通过 Start 返回的错误结束,而不会误判为已就绪。

type Runner added in v1.2.0

type Runner struct {
	// contains filtered or unexported fields
}

Runner 是 App 应用的命令行入口,封装应用实例与初始化回调。

func NewRunner added in v1.2.0

func NewRunner(setup SetupFunc, opts ...Option) *Runner

NewRunner 创建 Runner 实例。初始化失败不会立即退出进程, 错误会延迟到 RunE/Run 返回,以便调用方自行处理。 setup 为 nil 时记 ErrSetupFuncNil,由 RunE 返回。

func (*Runner) Run added in v1.2.0

func (b *Runner) Run()

Run 运行 Runner 应用,发生错误时以非零状态码退出进程。应用已构造 成功时经 app logger 输出结构化错误(与用户配置的日志格式一致,级别 error——此前走 log.Fatalln,WithLoggerProvider 路径下会被 std log 桥接成 info 级的嵌套渲染文本);构造失败(尚无 logger 可用)时回退 标准库 log。

func (*Runner) RunE added in v1.2.0

func (b *Runner) RunE() error

RunE 运行 Runner 应用并返回错误,由调用方决定错误处理方式。 实例与错误统一经 setupApp 获取:built/err 的读取全部落在 mu 保护内, 消除此前的无锁裸读(Run 的单次语义已阻止并发重入,锁主要保证 setup 回调只执行一次的既有契约)。 setup 失败时通过 Close 释放应用(兜底执行 OnPostStop 钩子、停止 提前启动的总线):setup 可能已注册服务/钩子后才失败,不释放会泄漏 ——与 torchwood 时代"cleanup 赋值后无论 RunE 成败都执行"的语义对齐。

type Server

type Server interface {
	Service
	// Addr 返回实际监听地址:Start 前(或 Listen 失败时)返回空字符串;
	// 使用随机端口(如 ":0")时返回 Listen 成功后的实际地址。
	Addr() string
	// AdvertiseAddr 返回 WithAdvertiseAddr 设置的对外宣告地址;未设置时
	// 返回空字符串。
	AdvertiseAddr() string
	// Ready 在 Listen 成功之后、Serve 之前关闭(语义同 Ready 接口)。
	Ready() <-chan struct{}
}

Server 是网络服务型 Service 的可选接口:在 Service 之上暴露实际监听 地址与就绪信号,供测试辅助(等就绪后拨号)与注册发现侧消费。 框架内 server/http 与 server/grpc 均实现该接口(debug 服务无宣告地址, 仅实现 Addr/Ready 部分)。

type Service added in v1.0.0

type Service interface {
	Name() string
	Lifecycle
}

Service 是可由 App 托管生命周期的命名服务。

func NewCommand added in v0.6.0

func NewCommand(fn CommandFunc, opts ...CommandOption) Service

NewCommand creates a new command service with the given function and options.

func NewOrderedServices added in v1.16.0

func NewOrderedServices(name string, services []Service, opts ...OrderedOption) Service

NewOrderedServices 是 OrderedServices 的选项化构造入口:启停语义与 OrderedServices 完全一致,额外接受组级选项(如 WithOrderedReadyTimeout)。

func OrderedServices added in v1.6.0

func OrderedServices(name string, services ...Service) Service

OrderedServices 将多个服务包装成一个 Service。 Init / Start 按传入顺序执行;Stop 逆序。允许嵌套。 子服务不要再单独 Register,否则会重复 Init/Start。 每个子服务的 Init / Start / Stop 都会记录 Info 日志(service=子服务名、 group=组名),组内启动停滞时据此定位到具体子服务。 每子服务就绪预算默认 10s;需要调整用 NewOrderedServices + WithOrderedReadyTimeout。

type ServiceFactory added in v1.0.0

type ServiceFactory interface {
	New() Service
	Options() FactoryOptions
}

ServiceFactory 按 FactoryOptions 描述的方式构建服务实例。

type SetupFunc added in v0.0.4

type SetupFunc func(app App) error

SetupFunc 是应用初始化回调,在 Runner 运行前执行,用于注册服务与 hooks。

type ShutdownErrors added in v0.7.1

type ShutdownErrors struct {
	// contains filtered or unexported fields
}

ShutdownErrors collects errors that occur during shutdown. It is safe for concurrent use.

func (*ShutdownErrors) Add added in v0.7.1

func (e *ShutdownErrors) Add(err error)

Add appends an error to the collection. Nil errors are ignored.

func (*ShutdownErrors) Error added in v0.7.1

func (e *ShutdownErrors) Error() string

Error returns a semicolon-separated string of all collected errors.

func (*ShutdownErrors) Errors added in v0.7.1

func (e *ShutdownErrors) Errors() []error

Errors returns a copy of all collected errors.

func (*ShutdownErrors) HasErrors added in v0.7.1

func (e *ShutdownErrors) HasErrors() bool

HasErrors returns true if any errors have been collected.

func (*ShutdownErrors) Unwrap added in v1.4.0

func (e *ShutdownErrors) Unwrap() []error

Unwrap returns all collected errors, allowing errors.Is / errors.As to match individual hook or service errors inside the collection.

type UnmarshalOption added in v1.9.0

type UnmarshalOption func(*UnmarshalOptions)

UnmarshalOption 定制 Unmarshal/UnmarshalKey 的解码行为。

func WithErrorUnused added in v1.14.0

func WithErrorUnused() UnmarshalOption

WithErrorUnused 报告配置子树中未被结构体消费的未知键(仅支持 UnmarshalKey)。

func WithStrictTypes added in v1.14.0

func WithStrictTypes() UnmarshalOption

WithStrictTypes 拒绝非字符串标量到集合的弱类型转换(如 brokers: 42 弱转为 []string{"42"} 的静默错配);字符串来源(环境变量注入)不受影响。

func WithTagName added in v1.9.0

func WithTagName(tag string) UnmarshalOption

WithTagName 指定匹配配置键所用的 struct tag(缺 tag 字段按小写字段名匹配)。

type UnmarshalOptions added in v1.9.0

type UnmarshalOptions struct {
	// TagName 非空时仅按该 struct tag 匹配配置键(无 tag 的字段按
	// 小写字段名匹配)。空值按 mapstructure → json → 小写字段名回退。
	TagName string
	// StrictTypes 拒绝非字符串标量到集合的弱类型转换(如 brokers: 42 被
	// 静默弱转为 []string{"42"}):启动期报错优于静默错值。字符串来源的
	// 弱转不受影响——环境变量注入的值恒为字符串("a,b" → 切表、"42" →
	// int 均为合法弱转),拒绝字符串会使 env 覆盖不可用。
	StrictTypes bool
	// ErrorUnused 报告配置子树中未被目标结构体消费的键(未知键,多为
	// 拼写错误)。仅 UnmarshalKey 支持(需要可枚举的配置子树,Unmarshal
	// 传入时返回明确错误);动态键的 map 字段整体视为已消费。
	ErrorUnused bool
}

UnmarshalOptions 是 Unmarshal/UnmarshalKey 的解码设置。 字段均为解码器无关概念,任意 Config 实现都应能解释。

Directories

Path Synopsis
Package boot 提供基于 Wire 依赖注入的应用引导,把依赖图中的 服务与 hooks 批量注册进应用。
Package boot 提供基于 Wire 依赖注入的应用引导,把依赖图中的 服务与 hooks 批量注册进应用。
Package buildinfo 承载编译期注入的构建信息:三个包级变量是 ldflags -X 的唯一注入目标(框架级真源,应用与 debug /version 端点共用,不再各持 一份):
Package buildinfo 承载编译期注入的构建信息:三个包级变量是 ldflags -X 的唯一注入目标(框架级真源,应用与 debug /version 端点共用,不再各持 一份):
client
grpc
Package grpc 提供框架的 gRPC 客户端:OpenTelemetry 插装 (otelgrpc client stats handler)、trace 与日志属性 (request_id/user_id)传播(写入 outgoing metadata)、默认调用超时。
Package grpc 提供框架的 gRPC 客户端:OpenTelemetry 插装 (otelgrpc client stats handler)、trace 与日志属性 (request_id/user_id)传播(写入 outgoing metadata)、默认调用超时。
http
出站熔断(ROADMAP G2):经典三态(closed/open/half-open)熔断器, 基于 sony/gobreaker/v2 封装——本包公共 API 零 gobreaker 类型 (实现可替换,kratos v3 的同款教训),配置经 CircuitBreakerOptions 映射,集成于 Client.Do 的最外层(重试之外:一次调用整体成败只计 一次,熔断打开时不再进入重试循环)。
出站熔断(ROADMAP G2):经典三态(closed/open/half-open)熔断器, 基于 sony/gobreaker/v2 封装——本包公共 API 零 gobreaker 类型 (实现可替换,kratos v3 的同款教训),配置经 CircuitBreakerOptions 映射,集成于 Client.Do 的最外层(重试之外:一次调用整体成败只计 一次,熔断打开时不再进入重试循环)。
contrib
cluster module
consul module
kafka module
log/zap module
pubsub module
registry module
schedule module
telemetry module
watermill module
zap module
Package debug 提供运维诊断服务:pprof 端点(仅建议监听本机回环地址)。
Package debug 提供运维诊断服务:pprof 端点(仅建议监听本机回环地址)。
package eventbus 提供 Lynx 一等消息总线:进程内状态协同与跨进程域事件的统一抽象。
package eventbus 提供 Lynx 一等消息总线:进程内状态协同与跨进程域事件的统一抽象。
internal
clock
Package clock 提供 lynx.Clock 的生产实现与测试用可控时钟。
Package clock 提供 lynx.Clock 的生产实现与测试用可控时钟。
propagation
Package propagation 是请求标识(request_id / user_id)传播规则的唯一归属: wire 键、入站值校验、日志属性构造与出站传播。
Package propagation 是请求标识(request_id / user_id)传播规则的唯一归属: wire 键、入站值校验、日志属性构造与出站传播。
serverkit
Package serverkit 是 HTTP / gRPC / debug 三个 server 适配器共享规则的 唯一归属:健康检查执行、有界优雅关停、请求标识传播与生命周期事件。
Package serverkit 是 HTTP / gRPC / debug 三个 server 适配器共享规则的 唯一归属:健康检查执行、有界优雅关停、请求标识传播与生命周期事件。
Package logging 提供框架的日志机制:slog.Handler 装饰器族与 请求级日志属性的上下文传播(request_id/user_id 等全链路字段)。
Package logging 提供框架的日志机制:slog.Handler 装饰器族与 请求级日志属性的上下文传播(request_id/user_id 等全链路字段)。
Package lynxtest 提供基于 Lynx 的应用的测试辅助。
Package lynxtest 提供基于 Lynx 的应用的测试辅助。
server
grpc
Package grpc 提供 gRPC 服务器服务,内置日志/恢复拦截器、 健康检查与反射服务,支持 OpenTelemetry 插装。
Package grpc 提供 gRPC 服务器服务,内置日志/恢复拦截器、 健康检查与反射服务,支持 OpenTelemetry 插装。
grpc/interceptor
Package interceptor 提供 gRPC 服务端拦截器:日志与 panic 恢复 (一元与流式各一套)。
Package interceptor 提供 gRPC 服务端拦截器:日志与 panic 恢复 (一元与流式各一套)。
http
按维度限流(v1.1 承诺回收,ROADMAP G3):每 key 一个令牌桶, key 由调用方从请求提取(路由 / 客户端 IP / 用户标识,预置提取器 见 RateLimitKeyPath 等)。
按维度限流(v1.1 承诺回收,ROADMAP G3):每 key 一个令牌桶, key 由调用方从请求提取(路由 / 客户端 IP / 用户标识,预置提取器 见 RateLimitKeyPath 等)。

Jump to

Keyboard shortcuts

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