magus v0.3.0 is out. See what's new
¶ View markdown source · ✎ Suggest an edit
3 min read

MGS3004: tool not ready

The binary is present, but the thing it talks to is not. This is MGS3003 one level deeper: the same category of failure - your environment rather than your code - caught for a client whose server is down.

[MGS3004] docker is installed but not ready. The op "docker" needs it running, and
`docker info` said:
  Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
  see: https://eli.gladman.cc/magus/reference/codes/sandbox/MGS3004/

The probe's own output is carried through rather than paraphrased. docker info names the socket and asks the right question; magus knows less about docker than docker does. The underlying failure is wrapped, so errors.Is still reaches it.

Why a version probe cannot catch this

A spell's version probe answers "what version is installed", and for a client/server tool that question is answerable with the server switched off. docker --version is client-only: it prints a version and exits 0 with no daemon running at all.

So the probe magus already ran was structurally incapable of noticing. The op forked, docker failed, and the run reported a build failure for a project with nothing wrong with it - the real explanation sitting in a captured log someone had to go open.

A readiness probe is the third question, distinct from the other two:

question declared by docker
does it exist? nothing - PATH lookup (MGS3003) docker
what version? mgs_getVersionProbe docker --version
is it usable now? mgs_getReadinessProbes docker info

At a terminal, magus waits first

When stdin is a TTY, a failed probe is retried for 30 seconds before the run gives up, so starting the daemon in another window lets the run continue instead of needing a re-run.

That grace period is interactive-only. Under CI or an agent nobody starts a daemon mid-run, so waiting there would burn 30 seconds per project to reach the same failure - and it would make a deterministic failure depend on how fast something else happened to start. Without a TTY the probe runs once and fails immediately.

Failing fast stays cheap either way: the check runs before the op forks, so nothing was consumed and a re-run replays from cache.

Declaring one

Keyed by tool name, the same convention the version probes use, and resolved through the op's own Command.bin - so no op restates which tool it runs.

export fun mgs_getReadinessProbes() > {str: Command} {
    return {"docker": Command{bin = "docker", args = ["info"]}};
}

Scoping is per tool, not per spell, and the docker spell is why. It drives docker and hadolint, and linting a Dockerfile talks to no daemon. A spell-scoped probe would make a lint wait on a service it never uses, which is a worse version of the bug this exists to fix.

Most spells need none. go, rustc, and node are self-contained; a spell that declares nothing is never gated.

Readiness never keys the cache

A readiness result is a precondition, not an input. docker info reports running containers and disk usage, so mixing it into a cache key would invalidate every entry on every run.

This is worth stating because the neighboring mechanism does the opposite: a version key exists precisely to enter the key. The two probes look alike and mean opposite things.

MGS3004readinesstoolsdockerdaemonerrorsmagusfile
Last updated (a103255f)
Glossary

Project

A directory magus recognizes as a unit of work (it has a magusfile); the unit of caching, scheduling, and dependency tracking. See workspace.

Magusfile

The magusfile.buzz that declares a project's targets (as export funs) and binds its spells. See targets.

Spell

A language/runtime adapter (e.g. go, md) that maps generic targets onto a toolchain's real commands. See spells.

Buzz

The language magusfiles are written in (the .buzz engine). See engines.

Cache

The content-addressed store magus consults before running a target, so unchanged work is skipped. See cache.

Sandbox

The restricted filesystem and environment a target runs in, so builds stay reproducible and side-effect-free. See sandbox.

Service

A long-running or shared process magus manages across runs, distinct from a one-shot target. See services.

Daemon

The background magus host that owns shared state such as services and the warm knowledge graph. See daemon.

CI

An ordinary magusfile-defined target you compose yourself with magus\needs - magus does not hardcode its stages. Magus.RunCI treats it specially only in that it strips the rw charm, it is the anchor magus affected ci keys off, and a selected scope with no project declaring it is a load error rather than a silent no-op. See targets.

Conventions

This page uses none of the site's convention markers. The full set is on the conventions page.