Systemd Service Dependencies and Ordering
Master systemd dependency directives: After, Before, Requires, Wants, BindsTo, and PartOf. Understand the difference between ordering and requirement dependencies.
Detailed Explanation
Controlling Service Start Order
Systemd manages service dependencies through two separate mechanisms: ordering (when to start) and requirements (what must be running). Understanding the difference is critical.
Ordering vs Requirements
| Directive | Type | Effect |
|---|---|---|
After= |
Ordering | Start this service after the listed units |
Before= |
Ordering | Start this service before the listed units |
Requires= |
Requirement | Listed units must be running; if they fail, this fails too |
Wants= |
Requirement | Listed units should start, but failures are tolerated |
BindsTo= |
Requirement | Stronger than Requires; if listed unit stops, this stops too |
PartOf= |
Requirement | If listed unit is stopped/restarted, this is too |
Common Mistake: After Without Requires
# WRONG: ordering without requirement
After=postgresql.service
This only ensures that if PostgreSQL is being started, our service starts after it. But it does NOT ensure PostgreSQL actually starts. You usually want both:
# CORRECT: ordering AND requirement
After=postgresql.service
Requires=postgresql.service
Wants vs Requires
Requires= creates a hard dependency. If the required service fails to start, your service also fails:
Requires=postgresql.service
# If PostgreSQL fails → our service fails too
Wants= creates a soft dependency. If the wanted service fails, your service starts anyway:
Wants=redis.service
# If Redis fails → our service starts anyway (with degraded functionality)
BindsTo — The Strongest Dependency
BindsTo= is like Requires but also stops your service when the dependency stops:
[Unit]
Description=Application requiring Docker
BindsTo=docker.service
After=docker.service
If docker.service stops (for any reason), the application service immediately stops too. This is essential for services that cannot function without their dependency.
PartOf — Group Management
PartOf= links services for grouped operations:
[Unit]
Description=Application Worker
PartOf=myapp.service
[Service]
ExecStart=/usr/local/bin/myapp-worker
When you run systemctl stop myapp.service or systemctl restart myapp.service, the worker service is also stopped/restarted. But the worker can still be managed independently.
Complex Dependency Example
A typical web application stack:
# database.service
[Unit]
Description=PostgreSQL Database
After=network.target
# cache.service
[Unit]
Description=Redis Cache
After=network.target
# api.service
[Unit]
Description=API Server
After=database.service cache.service
Requires=database.service
Wants=cache.service
# web.service
[Unit]
Description=Web Frontend
After=api.service
BindsTo=api.service
Start order: network → database + cache (parallel) → api → web
Debugging Dependencies
# Show dependency tree
systemctl list-dependencies myapp.service
# Show reverse dependencies
systemctl list-dependencies myapp.service --reverse
# Check for circular dependencies
systemd-analyze verify myapp.service
Use Case
Designing a multi-service application where a web frontend depends on an API server, which depends on a database and optionally a cache, with proper start ordering and failure propagation.