feat(app): component registry with ordered start/shutdown

What does this MR do and why?

Rust services on labkit-rs currently hand-write their own startup and shutdown boilerplate. This adds an opt-in app feature that gives them a small lifecycle runtime instead, matching what Go services already get from Go labkit v2's app.App.

A service describes each of its subsystems — a server, a background worker, a client — as a component and registers it with the app. The app brings components up in the order they were registered and takes them down in the reverse order, so a component can rely on the ones before it being up while it starts, and being torn down only after it has stopped. If a component fails to start, the ones already started are shut down again so the process doesn't come up half-alive.

This is the first step of the lifecycle work. It deliberately stops at ordered start/shutdown; OS signal handling, non-critical components with retry, and wiring the app into the shared logging/tracing/metrics runtime follow in the MRs stacked on top of this one.

Part of #39 (closed)

Closes part of #39 (closed)

Testing

Unit tests cover reverse-order shutdown, a critical start failure unwinding the components already started, and shutdown being a no-op before start. The doc example is compiled as a doctest.

Merge request reports

Loading
Loading