Skip to content

pi-dispatch v1.6.0

Choose a tag to compare

@github-actions github-actions released this 30 Aug 12:54
· 287 commits to main since this release

pi-dispatch v1.6.0 ships run.waitFor (issue #230): a trigger can now hold its job in the queue, unstarted and unbilled, until a condition clears. A label goes on an issue at 16:40 and the job runs when the deploy window opens at 09:00, or when the Jira parent reaches Done, or when last night's pipeline goes green.

What is new

  • Wait for an instant. "waitFor": [{ "after": "2026-09-01T09:00:00Z" }] defers the job to exactly that moment and costs nothing: one delayed wake, no polling, nothing to configure and nothing to install. The instant must carry its own zone, because "09:00" means one thing on your laptop and another in the container's UTC, and impossible dates are refused at load rather than rolled forward into a date nobody wrote.
  • Wait for anything you can write a script about. { "profile": "jira" } names one of your own check scripts, declared in PI_WAIT_PROFILES, which the worker runs on the host with the job's target id (acme/web#7, never a title or a body) and reads the exit code of: 0 to go, 3 for not yet, 2 if it will never clear, 1 if you could not tell. Five could not tells in a row refuses the job naming the script, which is what makes a broken check loud in minutes rather than silent for a day. Up to four conditions, all of which must clear, evaluated cheapest first.
  • A held job is visible, and cancellable. The /dispatch panel grows a held section while anything waits, showing what each job is waiting on and for how long, and hides it again when nothing does. dispatch_waits lists them; dispatch_wait_cancel stops one behind the operator confirm, which is the only way to cancel a held job short of editing redis by hand. Nothing reads a delayed job's data to build those rows, so no issue title or body reaches the panel.
  • The version skew is detected, not just documented. A receiver too old to carry the field would enqueue the job without its conditions and the worker would run it, producing a perfectly normal record, a normal panel row and a normal log line. Success is the least detectable failure available, and the whole premise of a wait is that running now is the destructive option. The worker now re-reads triggers.json at pickup and refuses such a job as wait-skew before any spend.
  • Bounds, because a wait is the one control that can cost nothing and still starve everything. A held job starts no container, so every spend cap is blind to it. Hence a per check timeout, a clamped interval that backs off, a check lease held below PI_CONCURRENCY, a maximum hold, a per job check count and a consecutive fault count, each with its own log line when it binds.

Upgrading

npm install all three packages together: this release moves the worker and admin to 1.6.0 and the receiver to 1.4.0, and the receiver's dependency range now requires the new worker rather than merely admitting it. Upgrade the receiver in the same install as the worker, before you write your first condition. Nothing changes for a deployment that declares no conditions: absent the field, every byte of every job is what it was.

Read docs/wait-for.md before writing a check, in particular the one liner trap. A pipeline ending in grep -q exits 1 for "no match", so the ordinary answer not yet would arrive as a counted fault and kill the job after five checks.