106 lines
3.8 KiB
Markdown
106 lines
3.8 KiB
Markdown
# Runtime Composition
|
|
|
|
This document describes how the `weatherapi` executable wires configuration,
|
|
database handles, application services, HTTP endpoints, renderers, and shutdown.
|
|
It is development-facing; operator commands belong in
|
|
[`docs/operations.md`](../operations.md), and configuration fields belong in
|
|
[`docs/config.md`](../config.md).
|
|
|
|
## Purpose
|
|
|
|
`cmd/weatherapi/main.go` is the composition root. It should stay thin and only
|
|
connect already-implemented packages. Endpoint logic, SQL, presentation logic,
|
|
and business read behavior belong outside `cmd`.
|
|
|
|
## Inputs and Outputs
|
|
|
|
Inputs:
|
|
|
|
- config path from `-config`, `WEATHERAPI_CONFIG`, or `config.yml`;
|
|
- feedapi YAML config containing `server`, `databases`, and `templates`;
|
|
- OS cancellation signals;
|
|
- database handles opened by feedapi.
|
|
|
|
Outputs:
|
|
|
|
- a configured feedapi HTTP server;
|
|
- registered `weatherapi` endpoint definitions;
|
|
- process logs for fatal startup errors and database close errors.
|
|
|
|
## Composition Flow
|
|
|
|
The executable:
|
|
|
|
1. sets standard logger flags with microsecond precision;
|
|
2. resolves the config path;
|
|
3. creates a context canceled by `os.Interrupt` or `SIGTERM`;
|
|
4. loads config with `feedapi/config.Load`;
|
|
5. requires at least one configured database;
|
|
6. opens all configured databases with `feedapi/db.OpenAll`;
|
|
7. selects the first configured database name as the primary store;
|
|
8. constructs `postgres.Repository` with the primary `*sql.DB`;
|
|
9. constructs `app.Service` over the repository;
|
|
10. builds HTTP endpoint definitions with `httpapi.Definitions`;
|
|
11. constructs a feedapi app with the DB registry and endpoints;
|
|
12. starts feedapi with the signal-aware context.
|
|
|
|
## Config Fields Used
|
|
|
|
Runtime composition uses:
|
|
|
|
- `server`: consumed by feedapi for HTTP runtime settings and default format;
|
|
- `databases`: opened by feedapi, with the first entry selected as primary;
|
|
- `templates`: consumed by feedapi for text-template loading.
|
|
|
|
Do not duplicate the config field reference here. Keep it in
|
|
[`docs/config.md`](../config.md).
|
|
|
|
## External Adapters Used
|
|
|
|
- `feedapi/config`: YAML loading.
|
|
- `feedapi/db`: database registry and lifecycle.
|
|
- `feedapi/app`: HTTP runtime construction and startup.
|
|
- `internal/adapters/outbound/postgres`: weather read repository.
|
|
- `internal/adapters/inbound/httpapi`: endpoint definition registry.
|
|
- `github.com/lib/pq`: Postgres driver registration through blank import.
|
|
|
|
## State and Lifecycle
|
|
|
|
`weatherapi` owns no durable weather state. Runtime state is limited to loaded
|
|
configuration, database pools, endpoint definitions, renderer/template
|
|
registries managed by feedapi, and the running HTTP server.
|
|
|
|
Database handles are closed with a deferred registry close. Close errors are
|
|
logged but do not change response behavior because they occur during shutdown.
|
|
|
|
## Failure Behavior
|
|
|
|
`run` wraps startup errors with operation context:
|
|
|
|
- `load config`
|
|
- `config.databases requires at least one entry`
|
|
- `open databases`
|
|
- `select primary database`
|
|
- `build app`
|
|
|
|
Errors returned by `a.Start(ctx)` are returned to `main`, which logs a fatal
|
|
`weatherapi failed: ...` message. Feedapi owns graceful HTTP shutdown after the
|
|
context is canceled.
|
|
|
|
## Tests to Inspect Before Changing
|
|
|
|
- `internal/app/service_test.go` for service wiring expectations.
|
|
- `internal/adapters/inbound/httpapi/endpoints_test.go` for endpoint registry
|
|
and runtime adapter expectations.
|
|
- Full `go test ./...` when runtime wiring, config behavior, or feedapi
|
|
integration changes.
|
|
|
|
## Invariants
|
|
|
|
- Keep `cmd/weatherapi` as composition code only.
|
|
- Preserve config path precedence: `-config`, `WEATHERAPI_CONFIG`, `config.yml`.
|
|
- Preserve first configured database as the primary weather store.
|
|
- Keep generic HTTP runtime behavior in feedapi.
|
|
- Keep endpoint definitions in the HTTP adapter.
|
|
- Keep SQL and row mapping in the Postgres adapter.
|