Docker Background Processes with the & wait Pattern

πŸ“– 2 minutes read

Docker containers expect one process. PID 1 runs, and when it exits, the container stops. But what if you need two processes running simultaneously β€” say a dev server and a background watcher, or a web server and a cron daemon?

The Naive Approach

You might try chaining commands:

command: '/bin/bash -c "process-a && process-b"'

This runs process-a, waits for it to finish, then runs process-b. Not parallel β€” sequential. And if process-a runs forever (like a dev server), process-b never starts.

The & wait Pattern

Background the processes with &, then wait for all of them:

command: '/bin/bash -c "process-a & process-b & wait"'

Here’s what happens:

  1. process-a & β€” starts in the background
  2. process-b & β€” starts in the background
  3. wait β€” blocks until ALL background processes exit

The wait is critical. Without it, bash reaches the end of the command string, exits, and Docker kills the container because PID 1 died.

Real-World Example

Running two webpack dev servers on different ports for separate frontend bundles:

services:
  node:
    build: .docker/builds/node
    command: '/bin/bash -c "npm install && PORT=8080 npm run dev & PORT=8081 npm run dev:widgets & wait"'
    ports:
      - "8080:8080"
      - "8081:8081"
    restart: always

Both dev servers run simultaneously in one container. If either crashes, wait still blocks on the surviving process, keeping the container alive.

When to Use This vs Separate Containers

Use & wait when:

  • Processes share the same filesystem and need the same volumes
  • They’re tightly coupled (same codebase, same dependencies)
  • You want simpler compose files for dev environments

Use separate containers when:

  • Processes have different resource needs or scaling requirements
  • You need independent health checks or restart policies
  • You’re running in production (one process per container is the Docker way)

Gotcha: Signal Handling

When Docker sends SIGTERM to stop the container, it goes to PID 1 (bash). By default, bash doesn’t forward signals to background processes. Add a trap if you need graceful shutdown:

command: '/bin/bash -c "trap \"kill 0\" SIGTERM; process-a & process-b & wait"'

kill 0 sends the signal to the entire process group, cleanly shutting down all backgrounded processes.

Daryle De Silva

VP of Technology

11+ years building and scaling web applications. Writing about what I learn in the trenches.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *