The deadline wrapper and the landing bound¶
A hold, a release and a requeue each change a job that may be running or waiting right now. They
are also the calls most likely to be retried: a supervisor that gets no answer decides again. If
the first call is only slow, and lands after the decision, it undoes what the second did. The
landing bound on this page is what go/dispatch calls CallBound, the value the adapter
declares in Declarations().CallBound.
The adapter prevents a late landing with two things: a deadline wrapper that stops a late call from starting, and the landing bound, which says when a call that did start can no longer take effect.
The wrapper¶
Each of these calls is sent as one short shell script, and the script does the checking on the Slurm host. This is the script for a hold, as the adapter's tests record it (the numbers vary):
trap '' PIPE HUP
_dsl_s=75
if [ "$(date +%s)" -le 1791797399 ]; then
TZ=UTC0 timeout -s KILL 25s scontrol update JobId=4242 StartTime=2036-10-11T20:00:07 </dev/null
_dsl_s=$?
fi
printf '\036DSL 0123456789abcdef0123456789abcdef call 1 %d\n' "$_dsl_s" >&2
exit "$_dsl_s"
In order, it:
- Ignores hangup and broken pipe. If the SSH session drops, the shell is hung up and what read
its stderr is closed. Either would kill the script between two calls, and a requeue's last
step would never run.
scontrolinherits the ignored signals, so a call in flight completes. - Starts with status 75. If the check refuses, 75 is what is reported and nothing runs.
- Checks the deadline on the host.
date +%sis the host's clock, truncated to whole seconds. The script goes ahead only while that is no later than the deadline's second minus one, which means only while the host's clock is before the deadline. - Runs
scontrolundertimeout -s KILL, so a hungscontrolis killed after the boundBrather than waiting for ever.TZ=UTC0makes the start time mean UTC. - Reports the status as a framed line on stderr, and exits with it.
The check is on the host for a reason: the caller's clock tells you when the caller sent a call, not
when it began to run. Only the machine that runs scontrol knows whether it is still in time. The
script is delivered whole, and over ssh carried base64 encoded, so a connection that drops partway
cannot run half of it.
The script is also detached: it runs to its own bound even if the context you passed is cancelled. Abandoning a call that is already on the host would turn a call that may have landed into one whose outcome you cannot know.
The landing bound¶
Passing the check means the call started in time. It does not mean it has finished. scontrol sends
its request to slurmctld and can be killed at B while the request is still on its way, or
waiting in the controller's socket. When the controller reads it, it applies it, unless the
authentication credential in the request has expired. Four things decide how late that can be:
| Term | Why it counts |
|---|---|
B, from MessageTimeout |
how long scontrol runs before it is killed: 2 × MessageTimeout + 5s. It counts because scontrol may retry within that bound, and each try carries a fresh credential |
| the credential TTL | a request older than the TTL is refused as expired, so no request lands later than this after it was made |
| the clock skew | the credential is encoded by munge on the login node and decoded on the controller, so its age is judged against two clocks that may differ |
| a margin of 5 seconds | for the controller to apply a request it has decoded; seen at 0.3 to 0.8 seconds |
Over SSH there are two more, because the deadline is in your clock and the check is in the host's: the offset between the two clocks, and half the round trip of reading the host's clock.
Their sum is Declarations().CallBound. The core treats a call as expired at its deadline plus the
call bound: past that point the call either landed or never will, and it is safe to decide again.
Choose deadlines, TTL and skew has the formula and
what to change.
The TTL was measured, not assumed. With slurmctld stopped, every update younger than munge's TTL
was applied when it resumed, and every older one was refused as Munge decode failed: Expired
credential; the cut-off fell within 5 seconds either side of 300 seconds. That was on 25.11.8 and
26.05.4 with munge. For auth/slurm the 60-second TTL comes from Slurm's source and has not been
measured.
The bound is tested, not just reasoned. TestLandingBound in the sind suite freezes slurmctld
between a call's lookup and its scontrol, so the request waits in the socket while timeout kills
the client, then lets the controller run. A call older than the TTL must change nothing; a younger
one may land, but before its deadline plus CallBound. See
Run the conformance suite against sind.
Why a requeue is three calls¶
Jobs are submitted with --no-requeue, so that Slurm never restarts one on its own authority:
every start of a job is dispatch's decision, with a new identity. To requeue one anyway, the
adapter sets the job's requeue bit for the length of the call. So Requeue is one script with
three calls, each behind the same deadline check:
scontrol update JobId=<id> Requeue=1scontrol requeue <id>, run only if call 1 succeededscontrol update JobId=<id> Requeue=0, run whenever call 1 was attempted at all, whatever call 2 returned
Call 3 runs even when call 1's result was lost, because the bit may have been set without your
seeing it. A script that is cut off after call 1, as a crash of the caller would, leaves the bit
set. That is visible: the object reports RequeueBit, and RestoreRequeueBit (one wrapped
Requeue=0) clears it. A requeue whose last step cannot be shown to have cleared the bit returns an
error saying the bit may be left set, so the caller knows to restore it. It is never reported as a
clean refusal while the bit may still be set.
How the answers are read¶
Each call prints one status line to stderr: a record separator, DSL, the script's random nonce, the
call's number and its status. The nonce means noise from a login script, or from scontrol itself,
can't be mistaken for a status. The reader refuses a line without the script's nonce, calls out of
order, text after the last status line, and a script exit status that is not the last call's. Any
of these is an outcome unknown, never a guess.
A failed scontrol counts as a refusal, meaning slurmctld decided and changed nothing, only if
every line it printed is <message> for job <id> with a message the adapter knows. Anything else
leaves the outcome unknown. Exit codes of the deadline wrapper
lists the statuses and the messages.