Skip to content

Handle DRMAA failures as terminal job statuses - #485

Merged
jmchilton merged 6 commits into
masterfrom
terminal-job-statuses
Aug 19, 2026
Merged

Handle DRMAA failures as terminal job statuses#485
jmchilton merged 6 commits into
masterfrom
terminal-job-statuses

Conversation

@jmchilton

Copy link
Copy Markdown
Member

Summary

  • map DRMAA JobState.FAILED to Pulsar's failed status
  • treat failed jobs as terminal in StatefulManagerProxy
  • stage partial outputs before sending the terminal failure callback
  • deactivate failed jobs and reclaim external-DRMAA working-directory ownership
  • add regression coverage for terminal lifecycle behavior and the DRMAA state mapping

This builds on and supersedes #482. The original mapping fix is retained as its own commit with Govind's authorship, and the changelog credits @gkr0110.

Root cause

PR #482 corrects the DRMAA-to-Pulsar mapping, but StatefulManagerProxy previously recognized only complete and cancelled as terminal. A DRMAA failure would therefore remain active, continue being polled, and never notify message-driven clients. The external DRMAA manager also reclaimed directory ownership only for successful completion.

The stateful terminal path now handles failed explicitly while leaving lost recoverable during startup. Both successful and failed jobs are postprocessed before their terminal callback is sent.

User impact

DRM-side failures such as scheduler submission rejection, walltime expiration, or resource-limit termination are reported as failed instead of complete. Message-driven Galaxy clients receive the terminal update, partial outputs can still be staged, and Pulsar releases the associated manager and working-directory state.

Validation

  • tox -e test-unit -- test/stateful_test.py test/manager_drmaa_test.py — 6 passed, 3 skipped locally because no DRMAA library is configured
  • Flake8 passed for pulsar and test
  • mypy passed for the changed Python modules and tests
  • git diff --check passed

gkr0110 and others added 5 commits August 18, 2026 11:59
BaseDrmaaManager._get_status_external() mapped JobState.FAILED to
status.COMPLETE, with a comment acknowledging it should map to FAILED
instead. This means any job that fails at the Slurm/DRMAA submission or
execution level (e.g. rejected for a missing/invalid account) is reported
back to Galaxy as a successful completion, with no output and no
indication anything went wrong.

status.FAILED already exists and is treated identically to status.COMPLETE
by status.is_job_done(), so this only affects the terminal status Galaxy
receives, not job-done detection.
StatefulManagerProxy only recognized COMPLETE and CANCELLED as terminal, so a
manager returning FAILED left the job active forever: never deactivated, polled
by ManagerMonitor for the life of the process, its active_jobs entry
re-registered on restart, and _deactivate_job never called on the proxied
manager.

Deactivating is only half of it. The terminal notification lived inside
do_postprocess, which ran only for COMPLETE, so even a deactivated FAILED job
told the client nothing - and message-driven clients never poll, so the job
hangs in running rather than being wrongly reported complete. FAILED now
postprocesses like COMPLETE, which preserves the staging the old
FAILED -> COMPLETE mapping gave remote_transfer deployments and reuses the
existing stage-then-notify ordering. CANCELLED still notifies nobody, because
the client initiated it and already knows.

status.is_job_done() looks like the obvious thing to reuse here and it is not:
it also counts LOST, which ExternalBaseManager returns for a job whose external
id has not been recovered yet. PulsarApp binds the message queue - and so
starts the monitor - before recover_active_jobs runs, so making LOST terminal
would race a restart into abandoning healthy jobs. Named the terminal set
instead and said why.

Also stop the preprocessing-failure path from re-deactivating on every poll; it
signals a state change once now, and does not stage or notify a second time for
a job that never launched.

The gap predates the DRMAA change - queued_cli has been able to return FAILED
since 2022.

integration_test_state.test_restart_finishes_job kills the job through the
DRMAA session rather than the manager, so it is a DRM-side failure; its
expectation encoded the bug and becomes "failed".
ExternalDrmaaQueueManager chowned the working directory back to the Pulsar user
only on COMPLETE. A job that fails DRM-side is just as done with the directory,
and without the chown Pulsar can neither read outputs nor clean up.
Covers the whole table rather than the one entry that changed - a state the
stateful manager does not recognize as terminal leaves the job hanging.

Also fixes tearDown calling setUp, which leaked a staging directory per test.
get_status starts postprocessing on its own thread and reports POSTPROCESSING
only while that thread has not finished. These jobs stage nothing, so the thread
can finish first and get_status correctly returns the terminal status - which
made every assertion on POSTPROCESSING a race. It lost on CI: the same commit
passed in one run and failed three tests in another.

Hold postprocessing on an event the test releases after observing the state.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jmchilton
jmchilton merged commit 9015ceb into master Aug 19, 2026
42 checks passed
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.

2 participants