Skip to content

When something is wrong ​

Start here:

bash
dqx doctor

It reports what is broken in this project and what to do about it — not a health score, a list of findings with severities and remedies.

What it checks ​

  • The machine: is the backend running, does something else hold 80 and 443, is mkcert's CA installed
  • The project: does every declared domain have a route and a certificate, does the docroot exist, is a container restarting in a loop
  • The application: can each site reach the schema its .env names, is QUEUE_CONNECTION set to something nothing is running, does the config declare a PHP image the stack does not run
  • The repository: does the config name a repository the checkout does not point at

Each finding says which of the two possible things is wrong, and neither is guessed at. When a project's .env asks for a database the config does not declare, dqx does not pick a winner — it tells you the two names and offers both ways to make them agree.

The failures that are hardest to see ​

These are the ones dqx was written for, because none of them announce themselves:

what you seewhat is actually happening
The site loads, but nothing savesThe schema exists but the user has no grant on it
Everything is 200, jobs never runQUEUE_CONNECTION is set and nothing is consuming the queue
One page is 500, the rest is fineA worker died and its container is restarting in a loop
It worked yesterdaySomebody changed the compose file and not the config, or the reverse
A colleague's build differsThe config names one repository and the checkout is at another
up never finishes, docker calls a healthy service unhealthyThe probe cannot run at all
Redis or the database refuses to start on data that was fineA floating tag is not the same image twice

Two that are worth their own command ​

A healthcheck that can never pass. Compose hands a test: written as a string to a shell whole, so the container tries to run [CMD-SHELL, and answers exit 127 — on every probe, for ever. The service behind it is usually fine; one project's Elasticsearch had recovered 62 indices and was serving while docker called it unhealthy. What you see is up refusing to call the project started.

bash
dqx healthchecks                 # what cannot run here
dqx healthchecks --write         # fix it: the check becomes a YAML list
dqx healthchecks --all ~/dockers # across every project under a directory

Measured on one fleet the first time this ran: 35 such checks in 23 of 32 projects.

An image tag that names no version. redis:alpine is whatever the engine you are on happened to pull last, so the same compose file is a different image on a colleague's laptop and on CI, which pulls fresh every run. For a service that keeps data on disk that is a format mismatch waiting:

# Can't handle RDB format version 15
# Fatal error loading the DB, check server logs. Exiting.

The data was fine — the reader was older. The message names neither the tag nor the version.

bash
dqx images                       # data-owning services on a floating tag, and the version behind it
dqx images --write               # pin them to the minor series
dqx images --outdated            # which pins have fallen behind upstream

Only services that own data are reported. The mail catcher keeps nothing a version can be wrong about, so it is left to follow upstream.

A pin is a promise that somebody raises it later, which is what --outdated is for. Raising one is a decision rather than a chore: read what changed in the data format first.

Keeping the house images fresh ​

bash
dqx update-images              # what this machine already has, brought up to date
dqx update-images --dry-run    # say what would be pulled, pull nothing
dqx update-images --major      # also cross a major version

Only what is already here. A machine on PHP 8.3 does not acquire the 8.5 image because it exists — the version is in the repository name, so "already here" answers it exactly. The old tool pulled a hardcoded list and cost everybody gigabytes for lines they never ran.

Within a line it does move forward: a tag like :3 is refreshed in place, and an exact 3.1.0 is taken to the newest 3.x. Crossing to 4.x is reported rather than done, because that is a decision about what a project runs, not an update. It only says "refreshed" when the digest actually moved.

dqx update is the project-scoped one: the images this project declares, whether or not they are here yet.

Asking a domain what it answers ​

bash
dqx verify

Every declared domain, with the status it actually returns. A 200 is not proof the application works, but a 404 or a certificate warning tells you where in the chain to look — see domains, DNS and certificates.

Logs ​

bash
dqx logs          # everything
dqx logs app      # one service

Starting over ​

bash
dqx down && dqx up      # the ordinary reset
dqx clean               # also removes the data directories a bind-mounted database leaves behind
dqx kill                # every project on every backend, and free 80 and 443
dqx kill --all          # that, and the runtimes too

dqx clean is the one that removes data. It asks first.

When dqx itself is the problem ​

dqx doctor reports what it can see. If it is silent and something is still wrong, the honest next step is the logs and then the issue tracker — with dqx info --json and dqx doctor --json attached, which is everything somebody else needs to see what you see.

dqx v1.1.0