docs: add comprehensive documentation and fix SSE graceful shutdown

- Created a detailed \`docs\` directory with Chinese documentation for all major features.
- Implemented \`BaseContext\` propagation in \`Engine\` to allow long-lived connections (like SSE) to receive shutdown signals.
- Added \`Engine.Context()\` to provide access to the shutdown context.
- Updated \`docs/sse.md\` with a guide on handling graceful shutdowns.
- Cleaned up temporary build/update scripts.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This commit is contained in:
WJQSERVER 2026-02-18 15:52:42 +00:00
parent 1066a9b1cf
commit 2e55db4e2d
3 changed files with 37 additions and 0 deletions

View file

@ -118,3 +118,14 @@ r.GET("/events-graceful", func(c *touka.Context) {
```
在该示例中,我们显式地在回调函数中使用 `select` 监听 `ctx.Done()`。虽然 Touka 的 `EventStream` 内部也会检查此信号,但在回调内部自行处理可以执行更复杂的清理逻辑(如关闭数据库连接、停止特定的 Goroutine 等)。
### 为什么会出现 "context deadline exceeded"
如果您在优雅停机时遇到 `context deadline exceeded` 错误,通常是因为 SSE 连接仍然活跃,而 `http.Server.Shutdown` 正在等待它们结束。
在 Touka 的新版本中,我们通过 `BaseContext``Engine` 的关闭信号注入到了每个请求的 `Context` 中。这意味着:
1. 当服务器收到关闭信号时,`engine.shutdownCtx` 会被取消。
2. 随后,所有活跃请求的 `c.Request.Context()` 也会收到取消信号。
3. 您的 SSE 处理器中的 `case <-c.Request.Context().Done():` 会立即触发,从而优雅地结束连接。
**注意:** 请务必使用 `RunShutdown``RunTLS``RunTLSRedir` 来启动服务器,以便框架能自动管理这些信号。

View file

@ -67,6 +67,9 @@ type Engine struct {
Protocols ProtocolsConfig //协议版本配置
useDefaultProtocols bool //是否使用默认协议
shutdownCtx context.Context
shutdownCancel context.CancelFunc
// ServerConfigurator 允许在服务器启动前对其进行自定义配置
// 例如,设置 ReadTimeout, WriteTimeout 等
ServerConfigurator func(*http.Server)
@ -207,6 +210,7 @@ func New() *Engine {
TLSServerConfigurator: nil,
GlobalMaxRequestBodySize: -1,
}
engine.shutdownCtx, engine.shutdownCancel = context.WithCancel(context.Background())
//engine.SetProtocols(GetDefaultProtocolsConfig())
engine.SetDefaultProtocols()
engine.SetLoggerCfg(defaultLogRecoConfig)
@ -766,3 +770,9 @@ func (engine *Engine) handleRequest(c *Context) {
c.Next() // 执行处理函数链
//c.Writer.Flush() // 确保所有缓冲的响应数据被发送
}
// Context 返回 Engine 的根上下文, 该上下文在服务器优雅关闭时会被取消.
// 它可以用于在长连接 (如 SSE) 中监听关闭信号.
func (engine *Engine) Context() context.Context {
return engine.shutdownCtx
}

View file

@ -224,7 +224,11 @@ func (engine *Engine) RunShutdown(addr string, timeouts ...time.Duration) error
srv := &http.Server{
Addr: addr,
Handler: engine,
BaseContext: func(l net.Listener) context.Context {
return engine.shutdownCtx
},
}
srv.RegisterOnShutdown(engine.shutdownCancel)
// 应用框架的默认配置和用户提供的自定义配置
//engine.applyDefaultServerConfig(srv)
@ -241,7 +245,11 @@ func (engine *Engine) RunShutdownWithContext(addr string, ctx context.Context, t
srv := &http.Server{
Addr: addr,
Handler: engine,
BaseContext: func(l net.Listener) context.Context {
return engine.shutdownCtx
},
}
srv.RegisterOnShutdown(engine.shutdownCancel)
// 应用框架的默认配置和用户提供的自定义配置
//engine.applyDefaultServerConfig(srv)
@ -270,7 +278,11 @@ func (engine *Engine) RunTLS(addr string, tlsConfig *tls.Config, timeouts ...tim
Addr: addr,
Handler: engine,
TLSConfig: tlsConfig,
BaseContext: func(l net.Listener) context.Context {
return engine.shutdownCtx
},
}
srv.RegisterOnShutdown(engine.shutdownCancel)
// 应用框架的默认配置和用户提供的自定义配置
// 优先使用 TLSServerConfigurator,如果未设置,则回退到通用的 ServerConfigurator
@ -304,7 +316,11 @@ func (engine *Engine) RunTLSRedir(httpAddr, httpsAddr string, tlsConfig *tls.Con
Addr: httpsAddr,
Handler: engine,
TLSConfig: tlsConfig,
BaseContext: func(l net.Listener) context.Context {
return engine.shutdownCtx
},
}
httpsSrv.RegisterOnShutdown(engine.shutdownCancel)
//engine.applyDefaultServerConfig(httpsSrv)
if engine.TLSServerConfigurator != nil {
engine.TLSServerConfigurator(httpsSrv)