Start here. This is the direct spoken answer to practice first.
Why this question matters
A running process is not necessarily ready to serve correct traffic, and a termination signal is not an immediate crash. The host lifecycle needs explicit boundaries for initialization, readiness, draining, and final stop.
I keep startup bounded and cancellation-aware. Required configuration and dependencies are validated before readiness turns healthy, while optional warmups can continue without blocking every deployment indefinitely. In .NET 10, BackgroundService.ExecuteAsync runs entirely as a background task, so even code before its first await no longer blocks other services from starting; earlier runtimes behaved differently. Startup-critical ordering belongs in StartAsync or explicit hosted lifecycle callbacks rather than depending on ExecuteAsync timing. On shutdown hosted services observe the stopping token, stop accepting new work, and finish or hand off in-flight work within the configured shutdown window.