Skip to content

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)

go
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 exit

App 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:

go
ctx := app.NewContext(context.Background(), core.ModeCron)

Capabilities — all return handles already bound to the request context:

go
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 | ModeTest

Unconfigured capabilities return nil (no panic).

Users & scoped data

go
ctx.SetUser(&core.ContextUser{ID: "u1", Email: "[email protected]"})
u := ctx.GetUser()

Type-safe per-request values (replaces v1's interface{} GetData/SetData):

go
core.Set(ctx, "trace_id", "abc")
id, ok := core.Get[string](ctx, "trace_id") // id is a string, no cast

The untyped ctx.GetData/SetData/GetAllData are still available.

Errors

go
return ctx.NewError(err, errmsgs.DBError)   // wraps err, logs at >=500

See error-handling.md.

Custom context (escape hatch)

go
bg, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
child := ctx.WithContext(bg) // same capabilities, different underlying context

Maintained by Passakon Puttasuwan & Dev Core Team.