# Go Service Lifecycle and Error Contracts

## Graceful shutdown

Coordinate lifecycle from the composition root:

1. construct dependencies and long-lived components;
2. start servers, consumers, and schedulers under an owned cancellation scope;
3. handle `SIGINT` and `SIGTERM`;
4. stop accepting new work;
5. cancel or stop pulling, then drain or safely return in-flight work;
6. flush required state with a bounded deadline;
7. close dependencies in reverse ownership order.

Every wait needs a timeout and defined forced-termination behavior. Do not acknowledge unfinished messages early or let diagnostic log flushing delay shutdown indefinitely.

## Application error contract

Keep internal causes available for logs and tracing while exposing a stable application error code and safe message at transport boundaries. Centralize transport mapping rather than formatting responses throughout services.

An error contract should define:

- stable machine-readable code ownership;
- safe user-facing message;
- wrapping or causal chain for diagnostics;
- mapping to HTTP, gRPC, or message behavior;
- whether callers may retry;
- compatibility rules for changing codes.

Do not return HTTP 200 for every failure unless the existing public contract explicitly requires it. Unknown errors must not leak SQL, credentials, stack traces, or vendor payloads.
