Read a preflight result¶
The adapter does not hand you a "preflight result" object. slurm.New runs preflight and fixes
its answers for the life of the Backend. You read them through two methods:
d := b.Declarations() // model.Declarations, no error
caps, err := b.Capabilities(ctx, nil) // map[model.Capability]model.Support
Through dispatch.Open, the core reads the same two methods and uses them to build a job's plan.
The tutorial prints both.
Capabilities and declarations lists every value and reason the
adapter can give. This page is about what to do with them.
What preflight does¶
Steps 1 to 7 read the cluster on every call to slurm.New. Steps 8 and 9 write, so they run only
on a backend that is not read-only, and only when there is no fresh cached result.
| Step | Does | Fails with |
|---|---|---|
| 1 | checks that sbatch, squeue, scontrol, scancel, sacct, timeout, date and base64 exist |
ErrUnsupported, naming the missing commands |
| 2 | reads sbatch --version |
ErrUnsupported, unless the release is 25.11 or 26.05 |
| 3 | reads scontrol show config: MinJobAge, KillWait, SlurmdTimeout, MessageTimeout, AccountingStoreFlags, PrivateData, AuthType and AuthInfo, and ClusterName when present. Nothing else in the dump is read |
an error with no sentinel if a key is missing, repeated or unreadable |
| 4 | lists your jobs with squeue --me --json=v0.0.44, which must report that data parser |
ErrUnreachable, or an error for an unreadable answer |
| 5 | reads $HOME on the host, which becomes the literal $HOME stands for in output.dir |
ErrUnsupported if it is not an absolute path |
| 6 | with transport: ssh only: reads the host's clock against yours |
an error with no sentinel if date +%s.%N does not print seconds and nanoseconds |
| 7 | finds the authentication credential's lifetime: an AuthInfo ttl=, else under auth/munge the TTL munge -n \| unmunge prints, after checking that munge and unmunge exist |
ErrUnsupported if munge or unmunge is missing; an error with no sentinel for an AuthInfo ttl= that is not a positive whole number, under any AuthType, or for unmunge output with no TTL |
| 8 | stops any probe job of yours that is more than 10 minutes old, left by a crashed preflight | the stop's error |
| 9 | submits the probe and tests holds, the controller's clock and accounting | ErrRejected if the cluster changes the probe; see Errors and error mapping for the rest |
Any read in steps 1 to 7 that fails to run, or exits non-zero, is ErrUnreachable.
A read-only backend runs steps 1 to 7 and never writes the cache. With a matching cached result it
takes Hold and AccountingHistory and the skew from it. Without one, both answers are unknown,
the execution window is 0, and CallBound is worked out with a skew of 0. Such a backend makes
no hold-family or requeue call, so its CallBound is informational.
Steps 1 to 7 are never cached. Because they run every time, a cluster that changes release or
loses a command is noticed on the next slurm.New.
Set your poll interval from the declarations¶
The adapter has no Watcher, so a supervisor polls it. PolledLoss for state, cause and
exit-code is the cluster's MinJobAge: poll at least that often, or a job can end and leave
squeue between two polls. The supervisor refuses a poll interval slower than the shortest bounded
window. If MinJobAge is too short for the poll you want, ask your administrator to raise it.
Act on Hold¶
| You see | Do |
|---|---|
yes |
nothing |
no, AuthType "..." has no known landing bound |
holds and requeue are unavailable on this cluster. Write recovery policies without a hold action, or ask your administrator about auth/munge or auth/slurm |
no, naming a probe step |
the cluster behaves differently from what holds rely on. Read the reason: it names the step, such as the hold not decoding from the job's start time. Prepare a cluster lists what the probe depends on |
unknown, read-only, and no cached probe |
open the backend writable once with a preflight.cacheDir, then open read-only backends with the same cache directory, adapter settings and target |
With Hold not yes, Hold and Release return dispatch.ErrUnsupported with the reason, and a
recovery rule whose action is hold reports the same answer from Rules.
Act on AccountingHistory¶
| You see | Do |
|---|---|
yes, comments are kept |
nothing |
yes, comments are not kept: ... |
finished jobs read from sacct have no submission or attempt number. Ask your administrator to add job_comment to AccountingStoreFlags |
no |
a job that has left squeue is dispatch.ErrNotFound. Poll within MinJobAge |
unknown |
treat it as no. The reason says why it could not be established |
Inspect and Ceased read sacct only when the answer is yes, so a read-only backend with no
cached probe never does.
Checking a result in your own program¶
Support.Value prints as yes, no or unknown, and Support.Source as declared, probed or
catalogue. To fail fast on a cluster that cannot hold:
caps, err := b.Capabilities(ctx, nil)
if err != nil {
return err
}
if h := caps[model.HoldCapability]; h.Value != model.Yes {
return fmt.Errorf("holds are %s on this cluster: %s", h.Value, h.Reason)
}
Where the probe's answers are kept¶
With preflight.cacheDir set, steps 8 and 9 results are stored in one file there, named for the
cluster, release and target. A result is reused only if all of these hold:
- it is younger than
preflight.maxAge(24 hours by default); - the cluster name, Slurm release and target are the same. For
transport: sshthe target is the transport, host, user, port and jump host; for any other transport it is the transport's name and the host name of the machine the adapter runs on, such aslocal:<hostname>; - a hash over your adapter settings and
scontrol show configis the same. Only the dump's "Configuration data as of" line is ignored.
Anything else, including a file that cannot be read, is a miss, and the probe runs again. The
directory must be a real directory of mode 0700 owned by you. A cache found anywhere else, or
reached through a symlink, is not read. A writable slurm.New that has to write into such a
directory fails with an unsafe-directory error rather than continue. Only a writable backend
creates the directory, after its probe; a read-only one never does.
The cached clock skew comes with it, so it is as old as the cache. Lower maxAge if clocks on
your cluster drift.