Skip to content

Auto-restart

DUMB includes an automatic restart system that monitors service health and restarts failed services to maintain system stability without manual intervention.


Overview

The auto-restart system provides:

  • Health monitoring - Periodic health checks for each service
  • Automatic recovery - Restart services that become unhealthy
  • Exponential backoff - Increasing delays between restart attempts
  • Restart limits - Prevent infinite restart loops
  • Grace periods - Allow services time to initialize
  • Startup lifecycle gating - Do not restart services while the stack is still assembling
  • Verified recovery - Count success only after the restarted service is healthy

Auto-restart status Auto-restart indicators


How it works

%%{ init: { "flowchart": { "curve": "basis" } } }%%
flowchart TD
    A([Service running])
    B{Health check}
    C{Threshold exceeded?}
    D{Restart limit reached?}
    E[Restart service]
    F([Stop retrying])
    G[Wait grace period]

    A ==> B
    B -- Healthy --> A
    B -- Unhealthy --> C
    C -- No --> B
    C -- Yes --> D
    D -- Not reached --> E
    D -- Reached --> F
    E ==> G
    G ==> B
  1. Startup gate - Monitoring waits until DUMB startup is ready or degraded
  2. Grace period - Each service receives its configured post-start grace
  3. Health check - DUMB verifies the process, configured ports, and—where a safe local endpoint exists—the application itself
  4. Unhealthy detection - Multiple consecutive failures trigger action
  5. Restart attempt - Service is stopped and restarted
  6. Recovery verification - Success is recorded only after health checks pass
  7. Repeat - Continue monitoring after restart

Health states and application probes

DUMB reports four application health states:

State Meaning Auto-restart behavior
Healthy Process, ports, and application probe passed Reset the consecutive-failure counter
Degraded The application is reachable but reports a warning, or an optional probe is unsupported/protected Keep the service running and show the reason
Starting The application explicitly reports initialization or migration work Keep waiting; do not count it as an Auto-restart failure
Unhealthy The process/port failed or the application endpoint reports a real failure Count toward unhealthy_threshold

Application probes are bounded, read-only, loopback requests cached briefly by the backend. Current probes include:

  • InfiniDysk backend /health
  • Servarr /ping for Sonarr, Radarr, Lidarr, Prowlarr, and Whisparr
  • Jellyfin /health, Emby application ping, and Plex /identity
  • Seerr status and Traefik Proxy Admin health
  • PostgreSQL pg_isready and pgAdmin ping
  • rclone's local RC version endpoint when RC is enabled

Services without a known safe application endpoint retain process and port checks. DUMB deliberately does not use content health, missing articles, indexer/provider warnings, or other external-integration checks as restart signals. Those conditions may require operator action, but restarting a healthy application usually does not fix them and can create a restart loop.

For InfiniDysk specifically, the maintained fork can keep its backend port open during a blocking database migration while /health returns 503 {"status":"migrating"}. DUMB reports this as Starting, so stack readiness waits for the real backend without repeatedly restarting a legitimate migration.


Configuration

Auto-restart is configured globally in dumb.auto_restart:

"dumb": {
  "auto_restart": {
    "enabled": false,
    "restart_on_unhealthy": true,
    "healthcheck_interval": 30,
    "unhealthy_threshold": 3,
    "max_restarts": 3,
    "window_seconds": 300,
    "backoff_seconds": [5, 15, 45, 120],
    "grace_period_seconds": 30,
    "services": []
  }
}

Configuration options

Option Default Description
enabled false Enable auto-restart globally
restart_on_unhealthy true Restart when health checks fail
healthcheck_interval 30 Seconds between health checks
unhealthy_threshold 3 Consecutive failures before restart
max_restarts 3 Maximum restarts within the window
window_seconds 300 Time window in seconds
backoff_seconds [5, 15, 45, 120] Backoff delays between restarts
grace_period_seconds 30 Seconds to wait after stack readiness or a later service launch before health checks
services [] Limit auto-restart to these process names

Backoff schedule

To prevent rapid restart loops, DUMB selects delays from the configured backoff_seconds list:

Attempt Delay
1 5 seconds
2 15 seconds
3 45 seconds
4+ 120 seconds

This is an explicit list, not a calculated multiplier. You can replace it with any ordered list of non-negative delays. Attempts beyond the list use its last value.


Restart limits

Services have a maximum number of restart attempts within a time window:

  • Default: 3 restart attempts in a rolling 300-second window
  • After reaching the limit, additional automatic attempts are suppressed while those attempts remain inside the window
  • Old attempts age out of the rolling window automatically
  • A manual start re-enables monitoring after an intentional stop, but does not erase the recorded rolling-window attempts

Restart limit reached

If a service keeps failing, investigate the root cause rather than increasing limits. Check logs for error messages.


Health checks

For each explicitly selected service, DUMB verifies:

  • the tracked PID still exists and is not a zombie; and
  • each configured port, frontend_port, backend_port, or webdav_port (including corresponding values in env) accepts a TCP connection.

There is no standalone health_check object in the current config. Add a service to dumb.auto_restart.services; its entry may inherit all global values or override selected policy fields:

"services": [
  {
    "process_name": "Riven Backend",
    "enabled": true,
    "unhealthy_threshold": 4,
    "grace_period_seconds": 60
  }
]

An empty services list monitors no services even when the global enabled flag is true. Use exact process names from GET /process/processes or select services in the frontend panel.

Slow applications can use a longer service override without delaying checks for the rest of the stack. A 300-second override is a reasonable starting point for a Seerr instance that performs migrations or a first-run frontend build. The stack-wide readiness deadline is configured separately under dumb.startup; see Startup lifecycle.


Monitoring restart status

Dashboard indicators

The dashboard shows auto-restart status for each service:

  • Restart count - Number of restarts in current window
  • Last restart - Timestamp of most recent restart
  • Health status - Current healthy/unhealthy state

API endpoints

Query restart status via the API:

# Get service status including restart info
curl 'http://localhost:3005/api/process/service-status?process_name=Riven%20Backend&include_health=true'

Response includes:

{
  "process_name": "Riven Backend",
  "status": "running",
  "healthy": true,
  "health_status": "healthy",
  "health_reason": null,
  "health_details": {
    "probe": "process_and_ports",
    "ports": [8080]
  },
  "restart": {
    "restart_attempts": 2,
    "restart_successes": 2,
    "restart_failures": 0,
    "recent_restart_attempts": 2,
    "pending": false,
    "next_restart_time": null,
    "disabled": false,
    "last_restart_time": 1736937000.0,
    "last_failure_reason": null,
    "last_exit_time": 1736936995.0,
    "last_exit_reason": "Port 127.0.0.1:8080 not responding",
    "unhealthy_count": 0,
    "unhealthy_threshold": 3
  }
}

WebSocket updates

Real-time restart events via /ws/status:

{
  "type": "status",
  "processes": [
    {
      "process_name": "Riven Backend",
      "status": "running",
      "healthy": true,
      "restart": {
        "restart_attempts": 2,
        "restart_successes": 2,
        "restart_failures": 0,
        "recent_restart_attempts": 2,
        "pending": false,
        "next_restart_time": null,
        "disabled": false,
        "last_restart_time": 1736937000.0,
        "last_failure_reason": null,
        "last_exit_time": 1736936995.0,
        "last_exit_reason": "Port 127.0.0.1:8080 not responding",
        "unhealthy_count": 0,
        "unhealthy_threshold": 3
      }
    }
  ]
}

Disabling auto-restart

Per-service

Remove a service from the monitored list, or retain an explicit disabled entry:

"services": [
  {
    "process_name": "Riven Backend",
    "enabled": false
  }
]

Globally

To disable auto-restart for all services, set dumb.auto_restart.enabled to false, or use the frontend panel. Per-service entries may remain stored for a later re-enable.


Best practices

Appropriate thresholds

  • Critical services (Plex, rclone): Lower threshold (2-3)
  • Background services (Zilean, NeutArr): Higher threshold (3-5)

Grace periods

  • Fast-starting services: 10-15 seconds
  • Database-dependent services: 30-60 seconds
  • Services with startup tasks: 60-120 seconds

Monitoring

  • Review restart counts regularly
  • Investigate services with frequent restarts
  • Check logs after restart events

Troubleshooting

Service keeps restarting

  1. Check service logs for errors
  2. Verify configuration is valid
  3. Ensure dependencies are running
  4. Check for port conflicts

Auto-restart not working

  1. Verify auto_restart.enabled is true
  2. Confirm the exact process name is present and enabled in auto_restart.services
  3. Check whether the restart limit was reached
  4. Confirm the configured service port is accurate and reachable on container loopback

Restart delay too long

  • Shorten the values in backoff_seconds
  • Review max_restarts and window_seconds before changing limits
  • Fix the underlying health failure instead of using a zero-delay retry loop