# ADR-002: Shutdown Ordering
## Status
Accepted (Implemented)
## Context
Services have dependencies. When shutting down, the order matters:
- Dependents should stop before their dependencies
- A service shouldn't be stopped while others still need it
Without proper ordering, dependents crash or misbehave when their dependencies disappear.
## Decision
### Shutdown All (system shutdown)
Use **reverse topological order**: dependents before dependencies.
```
Example:
database <- app
database <- worker
Startup order: database -> app -> worker
Shutdown order: worker -> app -> database
```
- Stop services one at a time
- Wait for each to fully exit before stopping the next
- Use SIGTERM -> timeout -> SIGKILL escalation
### Stop Single Service
**Cascade Rule**: First stop all services that depend on the target.
**Protection Rule**: Do NOT stop the target's dependencies (other services may need them).
```
Example:
database <- app
database <- worker
`zinit stop app`:
1. Nothing depends on app
2. Stop app
3. Do NOT stop database (worker still needs it)
`zinit stop database`:
1. app and worker depend on database
2. Stop app first
3. Stop worker
4. Now stop database
```
### Edge Cases
- **Circular deps**: Rejected at config validation
- **Conflicts**: Stopping A doesn't affect conflicting B
- **Oneshot**: Already exited, skip
- **Targets**: Virtual, mark inactive after members stop
## Implementation
**graph.rs**:
```rust
pub fn all_dependents_ordered(&self, id: ServiceId) -> Vec<ServiceId>
pub fn shutdown_order(&self) -> Vec<ServiceId> // reverse start order
```
**supervisor.rs**:
- `stop_all_services()`: Uses shutdown_order()
- `stop_service()`: Cascades to dependents first
## Consequences
- Clean shutdown without crashes
- Explicit dependency protection
- Predictable behavior for operators