Skip to content

Let an app version declare its own sbatch parameters - #584

Draft
leoschwarz wants to merge 10 commits into
mainfrom
feat/app-level-submitter-params
Draft

Let an app version declare its own sbatch parameters#584
leoschwarz wants to merge 10 commits into
mainfrom
feat/app-level-submitter-params

Conversation

@leoschwarz

@leoschwarz leoschwarz commented Aug 10, 2026

Copy link
Copy Markdown
Member

Every app currently gets whatever resources its submitter deployment was configured with, so there is no way to say "this app needs 24 cores and that one needs 1" short of running a submitter per app. An app version can now carry slurm_params — plain sbatch flags — which the SLURM submitter merges into the job it generates.

This restores the params half of the SubmitterRef field deleted in c778d65 ("Modernize submitter integration", #207), this time actually read by the submitter. The name half and the SubmittersSpec registry are deliberately not restored: B-Fabric decides which submitter runs a workunit, so a name could only select a profile inside the submitter already running, and the app version is a better selector for the same job — a devel version can carry different params than the released one, with no registry to keep in sync per environment.

Key points:

  • Precedence is submitter config < app version < workunit, so an app sets a default for itself, not a ceiling. A null value removes a flag the submitter would otherwise pass, which is the only way to unset one.
  • Reading the app spec at submit time is fail-safe: a missing file, bad YAML, an unknown version or an absent application_version all fall back to the submitter defaults with a warning. A submission must not fail over the app spec, since the job itself reports spec problems with far more context.
  • Rejected at validation time, so validate app-spec catches them before deployment: --output/--error/--chdir/--export (the submitter owns the job's logging, working directory and environment), ${workunit...} values (no workunit is in scope when a spec is evaluated), integer --time (YAML reads an unquoted 24:00:00 as 86400, which sbatch reads as minutes), and multi-line values (each flag becomes one #SBATCH line).

Trade-off worth a reviewer's opinion: RESERVED_SBATCH_FLAGS lives in the spec module, so specs/ now encodes something the submitter owns. The alternative was dropping those flags at merge time with a warning; validation-time rejection was chosen because a warning in a submitter log is not seen by the person editing the app.yml.

Out of scope here: adding cpus_per_task to the workunit whitelist, and translating a multi-node nodelist into --exclude of the partition complement.

Verification: 79 tests in tests/bfabric_app_runner/specs and .../bfabric_integration, basedpyright clean. The 6 failures in dispatch/test_dispatch_resource_flow.py are pre-existing on main (pandera on Python 3.14).

🤖 Prepared with assistance from Claude Opus 5 via Claude Code.

An app version may now carry extra sbatch flags in its app.yml, which the slurm
submitter merges between its own defaults and the per-workunit parameters. A null
value removes a flag the submitter would otherwise pass.

Reading the app spec at submit time never fails a submission: any problem falls
back to the submitter defaults with a warning, since the job itself reports app
spec errors with more context.

Flags that carry the job's logging, working directory and environment are
reserved, as are workunit variables, which are not in scope when an app spec is
evaluated.
Adds a task-shaped section to the app guide (what to write, what a user can still
override, how to unset a flag, which flags are refused, how to check it took
effect) plus the field-level reference and a changelog entry.
Two silent-wrongness cases, both caught at spec validation:

- YAML parses an unquoted 24:00:00 as the integer 86400, and sbatch reads a bare
  integer --time as minutes, so an app asking for a day would silently get 60.
- Each flag renders as one #SBATCH line, so a newline in a value would append
  lines to the generated job script.
The merge of main brought #600's stricter ApiResponseDataType, which made
Path(workunit.application.executable["program"]) a type error. Cast at the
call site as the sibling WrapAppYamlTemplate already does.
A workunit only carries partition, nodelist, mem and time, and 49 of 60
app-runner workunits sampled on TEST name the memory field "memory", which
SlurmWorkunitParams does not recognise and silently drops. "A user's own
choice still wins" was therefore false for memory on most apps.
The "memory" submitter parameter belongs to the legacy yaml___Slurm_executable,
which consumes it in bfabric.wrapper_creator.bfabric_submitter. Workunits served
by the app-runner submitter always carry --mem/--nodelist/--partition/--time, so
SlurmWorkunitParams never sees "memory" and nothing is silently dropped. The
four-flag limit on what a workunit can override does hold, and stays.
The field holds sbatch flags and is validated against SLURM semantics
(reserved #SBATCH flags, sexagesimal durations), so submitter_params
promised a generality the schema never had: no non-SLURM submitter could
consume the dict. Unreleased, so no app.yml carries the old key yet.

SlurmParameters.submitter_params keeps its name -- that one really is the
submitter deployment's own defaults from submitter.yml.
…g a single-version spec

_evaluate_app_params re-derived what resolve_app already knew: the
application_version parameter name and the spec lookup. Both now go through
AppSpec.for_parameters, so the submitter and the runner cannot drift apart on
which version a workunit resolves to.

That shared method also drops the requirement for an application_version when
the spec defines exactly one version, so an app that never had the parameter is
a drop-in. An explicitly named version is still taken literally, so nothing is
substituted silently -- which is the part #236 was closed over.

The callers keep their own error policy: the runner raises with the available
versions, the submitter warns and falls back to the submitter defaults.
@github-actions

Copy link
Copy Markdown
Contributor

📝 "TODO" Changes Detected

Summary: ✅ 2 "TODO"s removed

✅ Removed "TODO"s (2)

  • bfabric_app_runner/src/bfabric_app_runner/app_runner/resolve_app.py:16: # TODO this should be more generic in the future about the key for the app version (should be handled in AppSpec)
  • bfabric_app_runner/src/bfabric_app_runner/app_runner/resolve_app.py:17: # TODO logic to define "latest" version (should also be handled in AppSpec)

This comment is automatically updated when "TODO" changes are detected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant