Context & App
App owns long-lived resources (connection pools, base logger, shared HTTP client) and is built once at startup. IContext is the per-request/per-job container derived from the App — it carries every capability and is the ambient context.Context.
App (bootstrap)
env, _ := core.NewEnv()
db, _ := core.NewDatabase(env)
redis, _ := core.NewCache(env)
app, err := core.NewApp(env,
core.WithSQL("default", db),
core.WithSQL("readonly", replicaDB), // named connections
core.WithCache("default", redis),
core.WithMongo("default", mongo),
core.WithMQ(mq),
// core.WithLogger(customLogger), core.WithRequester(customClient)
)
defer app.Shutdown(context.Background()) // closes pools once, at exitApp methods: Config() *ENVConfig, ENV() IENV, Log() ILogger, NewContext(ctx, mode...) IContext, Shutdown(ctx) IError.
Pools live for the lifetime of the App — never per request. This fixes v1's bug where
IContext.Close()tore down shared pools on every request.
IContext (per request/job)
Delivery layers build it for you (WithHTTPContext, the scheduler, MQ consumers). To create one manually:
ctx := app.NewContext(context.Background(), core.ModeCron)Capabilities — all return handles already bound to the request context:
ctx.DB() // *gorm.DB (default connection, ctx-bound)
ctx.DBS("readonly") // named connection
ctx.Cache() // ICache / ctx.Caches("name")
ctx.DBMongo() // IMongoDB / ctx.DBSMongo("name")
ctx.MQ() // IMQ
ctx.Requester() // IRequester
ctx.ENV() // IENV
ctx.Log() // ILogger (with request_id/trace attrs)
ctx.Mode() // ModeHTTP | ModeCron | ModeMQ | ModeTestUnconfigured capabilities return nil (no panic).
Users & scoped data
ctx.SetUser(&core.ContextUser{ID: "u1", Email: "[email protected]"})
u := ctx.GetUser()Type-safe per-request values (replaces v1's interface{} GetData/SetData):
core.Set(ctx, "trace_id", "abc")
id, ok := core.Get[string](ctx, "trace_id") // id is a string, no castThe untyped ctx.GetData/SetData/GetAllData are still available.
Errors
return ctx.NewError(err, errmsgs.DBError) // wraps err, logs at >=500See error-handling.md.
Custom context (escape hatch)
bg, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
child := ctx.WithContext(bg) // same capabilities, different underlying context