Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Dependencies

Dependencies let you control process startup order. Each dependency is polled in a loop until it is satisfied or its timeout expires. A process is not started until all of its dependencies are met.

Dependency types

HTTP health check

Wait for an HTTP endpoint to return an expected status code.

depends:
  - url: http://localhost:8080/health
    code: 200
FieldTypeRequiredDefaultDescription
urlstringyesURL to GET
codeintegeryesExpected HTTP status code
poll_intervalfloatno1.0Seconds between polls
timeout_secondsintegerno60Seconds before giving up

The HTTP client uses a 5-second per-request timeout. Only the status code is checked — the response body is ignored.

TCP connect

Wait for a TCP port to accept connections.

depends:
  - tcp: "127.0.0.1:5432"
FieldTypeRequiredDefaultDescription
tcpstringyesAddress in host:port form
poll_intervalfloatno1.0Seconds between polls
timeout_secondsintegerno60Seconds before giving up

Each poll attempt uses a 1-second connect timeout.

File exists

Wait for a file to appear on disk.

depends:
  - path: /tmp/ready.flag
FieldTypeRequiredDefaultDescription
pathstringyesPath to check

Poll interval is 1 second. Timeout is 60 seconds. These are not configurable for this dependency type.

File contains key

Wait for a file to contain a specific key, with optional value extraction into the process environment.

depends:
  - file_contains:
      path: /tmp/config.yaml
      format: yaml
      key: "$.database.url"
      env: DATABASE_URL
FieldTypeRequiredDefaultDescription
pathstringyesPath to the file
formatstringyes"json" or "yaml"
keystringyesJSONPath expression (RFC 9535)
envstringnoIf set, the resolved value is injected as this env var
poll_intervalfloatno1.0Seconds between polls
timeout_secondsintegerno60Seconds before giving up

The key field accepts a JSONPath expression (RFC 9535). Use $ to refer to the document root, . to traverse nested maps, and bracket notation for array filtering. The first matching value is used. Scalar values (strings, numbers, booleans) are converted to strings. Null values are treated as missing. Mappings and sequences are serialized as JSON strings.

Array filtering example — extract rpc from the entry where alias == "local":

depends:
  - file_contains:
      path: /tmp/sui_client.yaml
      format: yaml
      key: "$.envs[?(@.alias == 'local')].rpc"
      env: SUI_RPC_URL

When env is specified, the value at key is extracted and injected into the dependent process’s environment under that variable name. This happens after all dependencies are satisfied, just before the process is spawned. See Templates for more on passing data between processes.

Process exited

Wait for another process to exit successfully (once: true processes only, in practice).

depends:
  - process_exited: migrate
FieldTypeRequiredDefaultDescription
process_exitedstringyesName of the process to wait for

Poll interval is 100ms. Timeout is 60 seconds. These are not configurable for this dependency type.

This dependency is satisfied when the named process has exited (with any exit code). It is typically used with once: true processes like migrations or setup scripts.

For for_each processes, a process_exited dependency on the template name is satisfied only when all fan-out instances have exited.

How polling works

When a process has dependencies, procman spawns a dedicated waiter thread that evaluates dependencies in declaration order. Each dependency is fully satisfied before the next one is evaluated:

  1. Start with the first dependency.
  2. Poll the current dependency using its check function.
  3. If the check succeeds, log dependency satisfied: <description> and advance to the next dependency.
  4. If the check fails for the first time, log dependency not ready: <description> (logged only once per dependency to avoid noise).
  5. If the check fails, sleep for the dependency’s poll_interval and retry.
  6. Once all dependencies are satisfied, proceed to spawn the process.

This sequential evaluation prevents stale-data races — for example, a file_contains dependency listed after a process_exited dependency will not be checked until the process has actually exited, ensuring it reads freshly generated data rather than leftovers from a prior run.

Timeout behavior

Each dependency’s timeout clock starts when that dependency begins being evaluated (i.e., when the previous dependency is satisfied), not when the waiter thread starts. This means total wall-clock time for a process with multiple dependencies is the sum of individual wait times rather than the maximum.

If any single dependency exceeds its timeout:

  1. The waiter logs dependency timed out: <description>.
  2. The global shutdown flag is set.
  3. All processes are torn down (SIGTERM, then SIGKILL after a grace period).

A timed-out dependency is fatal — procman does not continue with partial dependencies.

Circular dependency detection

At parse time, procman builds a directed graph from process_exited dependencies and runs a DFS cycle detection pass. If a cycle is found, parsing fails with an error showing the full cycle path:

Error: circular dependency: a -> b -> c -> a

Self-dependencies (a -> a) are also detected. References to process names not defined in the config file are rejected with:

Error: process 'a' depends on unknown process 'nonexistent'

Environment variable expansion in paths

The url, tcp, path, and file_contains.path fields support environment variable expansion at parse time. See the Configuration chapter for the full syntax.

depends:
  - path: $HOME/.config/app/ready.flag
  - tcp: "${DB_HOST}:5432"