Skip to content
Daemon

Lifecycle

Starting and stopping

kache daemon start      # start in background, blocks until the socket is ready
kache daemon stop       # graceful shutdown (drains pending uploads, up to 30s)
kache daemon restart    # restart in place (service-manager kickstart, else stop + fresh spawn)
kache daemon            # status: binary version/epoch, service install state, running/stopped, socket path, log location, and (if running) the daemon's version/epoch
kache daemon log        # stream the daemon log (follows like tail -f)

kache daemon restart recovers a wedged daemon in three tiers: it first asks the service manager (launchd/systemd) to kickstart it, then falls back to killing any lingering kache daemon run processes and wiping stale socket/lock/state files, then spawns a fresh background daemon.

kache daemon run starts the daemon in the foreground. This is mostly useful for debugging. By default only warnings and errors print to stderr; set KACHE_LOG=kache=info (or kache=debug) for verbose daemon logs.

Installing as a system service

For the daemon to survive reboots and start automatically, install it as a system service.

kache daemon install

This creates a launchd plist at ~/Library/LaunchAgents/ninja.kunobi.kache.plist and loads it. The daemon will start on login and restart if it crashes.

To remove it:

kache daemon uninstall
kache daemon install

This creates a systemd user unit (kache.service) and enables it. The daemon runs under your user session.

systemctl --user status kache.service
journalctl --user -u kache.service   # logs (or use `kache daemon log`)

To remove it:

kache daemon uninstall

Automatic restart on binary update

When you update kache, the old daemon and the new wrapper would disagree on RPC protocol versions. kache handles this automatically.

Each process tracks a build epoch — the modification time of the kache binary. The daemon reads the client's epoch from incoming Upload/Stats/BuildStarted requests; when a client binary is newer, the daemon sets its own shutdown flag and self-terminates once in-flight work drains. If it was installed as a service, launchd/systemd restarts it with the new binary; otherwise the next upload or CLI/monitor command auto-starts it. The next RPC call hits the fresh daemon. You never need to manually restart the daemon after an update.

The daemon applies the same self-restart to config changes. It loads its config once at startup, so it periodically re-fingerprints the active config file; when the file changes on disk (e.g. you edit local_max_size), it schedules the same graceful restart and comes back up with the new config — no manual kache daemon stop needed. Only the config file is watched: a running process's environment is fixed, so KACHE_* env overrides still apply only to freshly started daemons.

Restarting the daemon adds no latency to in-progress rustc invocations: the remote-check hot path never starts the daemon (it skips straight to compilation on a miss). Only the background upload path will lazily (re)start a downed daemon.

Idle shutdown

The daemon can auto-exit after a stretch with no connections, so zombie daemons don't accumulate when you aren't building. It is re-spawned on the next build.

# config.toml
daemon_idle_timeout_secs = 600   # exit after 10 min idle; 0 disables

You can also set KACHE_DAEMON_IDLE_TIMEOUT (seconds). The default is 600 seconds (10 minutes). Set it to 0 to disable the watchdog so the daemon runs indefinitely until you stop it, the binary updates, or the OS signals it.

Lifecycle internals

A few behaviors worth knowing about:

  • Single instance: a second kache daemon run exits cleanly (code 0) if another process holds the run lock or the socket is already live, so launchd/systemd KeepAlive won't loop. Stale socket files are removed on startup when nothing is listening.
  • Background log file: auto-started daemons write stderr to <socket>.log next to the daemon socket (Linux ~/.cache/kache/daemon.log, macOS ~/Library/Caches/kache/daemon.log). It is reset to a --- log rotated --- marker once it grows past 2 MiB. kache daemon log tails this file.
  • Graceful drain: on shutdown the daemon closes its upload queue and waits up to 30 s for in-flight S3 uploads to finish before aborting workers.

Offline behavior

If the daemon is down or unreachable when the wrapper makes an RPC call, the wrapper continues without it. This affects:

  • Remote checks: skipped — the wrapper goes straight to compilation on a local miss
  • Upload jobs: the wrapper tries to (re)start the daemon and re-send; the job is dropped only if the daemon can't be started. It never fails the build.
  • Prefetch: skipped for the current build session

The monitor shows daemon: offline when the daemon hasn't responded in the last refresh cycle. Common causes:

SymptomLikely cause
daemon: offline after rebootService not installed, or install is user-scoped and session hasn't started
daemon: offline after updateEpoch mismatch restart in progress — wait a second and refresh
daemon: offline continuouslyCheck kache daemon log for startup errors

When the monitor shows daemon: offline, it falls back to reading the local store and event log directly, so the Build and Store tabs still show accurate data.

Available for:
Apple macOS logomacOSMicrosoft Windows logoWindowsLinux logoLinux
Download Kunobi