# app app orchestrates modular application setup and teardown for Go services. ## Install ```bash go get gitea.auvem.com/go-toolkit/app ``` ## Quick start ```go package main import ( "context" "fmt" "log/slog" "gitea.auvem.com/go-toolkit/applog" "gitea.auvem.com/go-toolkit/app" ) func main() { lifecycle := app.NewLifecycle( applog.AppLogOpts{ConsoleOutput: os.Stderr}.Module(), ) defer func() { if err := lifecycle.Teardown(); err != nil { fmt.Println("shutdown error:", err) } }() if err := lifecycle.Setup(); err != nil { panic(err) } ctx := lifecycle.Context(context.Background()) _ = ctx lifecycle.Logger().Info("ready") } ``` ## Concepts - **Module** — a named subsystem with optional `Setup`, `Teardown`, and `Depends` - **Lifecycle** — holds modules and runs setup/teardown in dependency order - **Setup** — initializes all modules registered via `NewLifecycle` - **Require** — adds and initializes modules on demand (typical for CLI subcommands via [appcli](https://gitea.auvem.com/go-toolkit/appcli)) - **Autoload** — when enabled (default), `Depends` names are set up automatically before the dependent module ## Dependencies List dependency module **names** in `ModuleOpts.Depends`. Dependent modules must be registered in the same lifecycle (via `NewLifecycle` or an earlier `Require`). Circular dependencies return an error. ## Teardown Always defer `lifecycle.Teardown()`. Teardown runs in **reverse setup order** so dependents shut down before their dependencies. ## Context Use `lifecycle.Context(ctx)` so downstream code and `appcli` commands can call `app.LifecycleFromContext(ctx)`. ## Companion packages | Package | Role | |---------|------| | [applog](https://gitea.auvem.com/go-toolkit/applog) | slog + tint logging module | | [appcli](https://gitea.auvem.com/go-toolkit/appcli) | urfave/cli v3 integration | | [dbx](https://gitea.auvem.com/go-toolkit/dbx) | database module | | [migrate](https://gitea.auvem.com/go-toolkit/migrate) | goose migrations module | ## API reference | Symbol | Description | |--------|-------------| | `NewLifecycle(modules...)` | Create lifecycle with optional initial modules | | `Lifecycle.Setup()` | Set up all registered modules | | `Lifecycle.Teardown()` | Tear down in reverse setup order | | `Lifecycle.Require(modules...)` | Set up modules on demand | | `Lifecycle.RequireWithOpts(opts, modules...)` | Require with custom logger or unique-name enforcement | | `Lifecycle.GetModule(name)` | Look up a registered module | | `NewModule(name, opts)` | Define a module | | `LifecycleFromContext(ctx)` | Retrieve lifecycle from context | ## Error handling - Partial setup failure rolls back already-initialized modules - `Teardown` joins errors from all modules but attempts every teardown - A second `Setup` or `Teardown` on the same lifecycle returns an error