biomero package
biomero.slurm_client module
- class biomero.slurm_client.SlurmClient(host='slurm', user=None, port=None, config=None, gateway=None, forward_agent=None, connect_timeout=None, connect_kwargs=None, inline_ssh_env=True, slurm_data_path: str = 'my-scratch/data', slurm_images_path: str = 'my-scratch/singularity_images/workflows', slurm_converters_path: str = 'my-scratch/singularity_images/converters', slurm_model_paths: dict = None, slurm_model_repos: dict = None, slurm_model_images: dict = None, converter_images: dict = None, slurm_model_jobs: dict = None, slurm_model_jobs_params: dict = None, slurm_model_use_gpu: dict = None, slurm_script_path: str = 'slurm-scripts', slurm_script_repo: str = None, init_slurm: bool = False, track_workflows: bool = True, enable_job_accounting: bool = True, enable_job_progress: bool = True, enable_workflow_analytics: bool = True, sqlalchemy_url: str = None, config_only: bool = False, slurm_data_bind_path: str = None, slurm_conversion_partition: str = None, slurm_default_partition: str = None, sacct_start_time: str = None, sacct_days_ago: int = None, env_file_submission: bool = False, inject_gpu_flag: bool = False, gpu_partition: str = None, gpu_gres: str = None, gpu_gpus: str = None, slurm_global_job_params: list = None, slurm_image_pull_via_sbatch: bool = False, image_pull_cpus: str = None, image_pull_mem: str = None, apptainer_tmpdir: str = None, apptainer_cachedir: str = None, slurm_zip_cmd: str = None, analytics_rebuild_start_time: str = None, analytics_rebuild_days_ago: int = None, image_pull_time: str = None, image_pull_concurrency: int = 1, image_pull_partition: str = None, remote_shallow_zarr: bool = False, remote_shallower_image: str = 'cellularimagingcf/biomero-shallower:latest', remote_shallower_version: str = None, remote_shallower_workers: int = 1, remote_shallower_partition: str = None, remote_shallower_mem: str = None, remote_shallower_time: str = None, job_status_attempts: int = 5, job_status_retry_seconds: float = 3, ssh_recovery_timeout: int = 900, slurm_lock_cmd: str = 'flock -w {wait_seconds} -E {busy_exit_code} {lock_file}')[source]
Bases:
ConnectionA client for connecting to and interacting with a Slurm cluster over SSH.
This class extends the Connection class, adding methods and attributes specific to working with Slurm.
SlurmClient accepts the same arguments as Connection. Below only mentions the added ones:
The easiest way to set this client up is by using a slurm-config.ini and the from_config() method.
- slurm_images_path
The path to the directory containing the Singularity images for Slurm jobs.
- Type:
- slurm_converters_path
The path to the directory containing the Singularity images for file converters.
- Type:
- slurm_model_paths
A dictionary containing the paths to the Singularity images for specific Slurm job models.
- Type:
- slurm_model_repos
A dictionary containing the git repositories of Singularity images for specific Slurm job models.
- Type:
- slurm_model_images
A dictionary containing the dockerhub of the Singularity images for specific Slurm job models. Will fill automatically from the data in the git repository, if you set init_slurm.
- Type:
- slurm_script_path
The path to the directory containing the Slurm job submission scripts on Slurm.
- Type:
- slurm_script_repo
The git https URL for cloning the repo containing the Slurm job submission scripts. Optional.
- Type:
Example
# Create a SlurmClient object as contextmanager
with SlurmClient.from_config() as client:
# Run a command on the remote host
result = client.run(‘sbatch myjob.sh’)
# Check whether the command succeeded
- if result.ok:
print(‘Job submitted successfully!’)
# Print the output of the command
print(result.stdout)
Example 2:
# Create a SlurmClient and setup Slurm (download containers etc.)
with SlurmClient.from_config(init_slurm=True) as client:
client.run_workflow(…)
- build_sbatch_wrap_command(wrapped_command: str, *, job_name: str, output_path: str, job_params: List[str] | None = None) str[source]
Build an
sbatch --wrapcommand that honours the site defaults.- Parameters:
wrapped_command (str) – The shell command the job runs.
job_name (str) – Slurm job name.
output_path (str) – Remote path of the job log; may contain Slurm filename patterns such as
%j.job_params (Optional[List[str]]) – Resource flags; defaults to
get_job_params(), which applies the configured default partition and globalsbatch_*parameters, except the flags this method sets itself (SBATCH_WRAP_OWNED_FLAGS).
- Returns:
The
sbatchcommand, printing the job ID on submission.- Return type:
- cancel_slurm_jobs(slurm_job_ids: List[int]) Result | None[source]
Cancel Slurm jobs, for example when the workflow they belong to is cancelled.
Cancelling a job that already ended is not an error for the caller: the job is gone either way, so this logs what Slurm answered and returns the result instead of raising.
The command restricts
scancelto jobs owned by the cluster account BIOMERO connects with (--user, which Slurm documents as “restrict the scancel operation to jobs owned by the given user”). An account with Slurm operator, admin or coordinator rights may otherwise cancel other users’ jobs, so a wrong or stale job ID can never hit a job that is not BIOMERO’s. It uses--user="$USER"rather than--me, which older Slurm versions lack.- Parameters:
slurm_job_ids (List[int]) – The job IDs of the jobs to cancel.
- Returns:
- The result of the
scancelcommand, or None when none of the IDs is a valid job ID.
- The result of the
- Return type:
Result
- check_job_status(slurm_job_ids: List[int], env: Dict[str, str] | None = None) Tuple[Dict[int, str], Result | None][source]
Check the status of Slurm jobs with the given job IDs.
Note: This doesn’t return job arrays individually. It takes the last value returned for those sub ids (generally the one still PENDING).
- Parameters:
- Returns:
A tuple containing the status per input ID and the result of the command execution. Without any valid (positive integer) job ID nothing is run: it returns
({}, None).- Return type:
- Raises:
SSHException – If the command fails, or sacct returns no job rows after
job_status_attemptsattempts.
- check_remote_commands_available() List[str][source]
Check that the cluster has the commands that recovery relies on.
Tracked submissions, result archives and input extraction repeat safely after a lost connection only with a lock command (
slurm_lock_cmd,flockby default) and with Slurm accounting (sacct), which finds a job whose submission reply was lost. With Info-ZIP asslurm_zip_cmd, extraction also needsmktempand afindwith-cnewer(GNU findutils; only the presence offindis checked). A missing command is logged as a WARNING and does not stop the setup.- Returns:
The executables that were not found.
- Return type:
List[str]
- cleanup_tmp_files(slurm_job_id: str, filename: str = None, data_location: str = None, logfile: str = None) Result[source]
Cleanup zip and unzipped files/folders associated with a Slurm job.
- Parameters:
slurm_job_id (str) – The job ID of the Slurm script.
filename (str) – The zip filename on Slurm.
data_location (str, optional) – The location of data files on Slurm. If not provided, it will be extracted from the log file.
logfile (str, optional) – The log file of the Slurm job. If not provided, a default log file will be used.
- Returns:
The result of the cleanup operation.
- Return type:
Result
Note
The cleanup process involves removing the specified zip file, the log file, and associated data files and folders.
Example
# Cleanup temporary files for a Slurm job client.cleanup_tmp_files(“12345”, “output.zip”)
- convert_param_type_to_omtype(param_type: str, _default, *args, **kwargs) Any[source]
Convert a generic type to an OMERO type and instantiates it with args/kwargs.
Note that Cytomine has a Python Client, and some conversion methods to python types, but nothing particularly worth depending on that library for yet. Might be useful in the future perhaps. (e.g. https://github.com/Cytomine-ULiege/Cytomine-python-client/ blob/master/cytomine/cytomine_job.py)
- Parameters:
param_type (str) – The param type to convert.
_default – The default value. Required to distinguish between float and int.
*args – Additional positional arguments.
**kwargs – Additional keyword arguments.
- Returns:
The converted OMERO type class instance or None if errors occured.
- Return type:
Any
- convert_url(input_url: str, ext: str = '.json') str[source]
Convert the input GitHub URL to an output URL that retrieves the ‘descriptor.json’ file in raw format.
- Parameters:
- Returns:
The output URL to the ‘descriptor.json’ file.
- Return type:
- Raises:
ValueError – If the input URL is not a valid GitHub URL.
- copy_zip_locally(local_tmp_storage: str, filename: str) Result[source]
Copy a zip file from Slurm to the local server.
Note about (Transfer)Result:
Unlike similar classes such as invoke.runners.Result or fabric.runners.Result (which have a concept of “warn and return anyways on failure”) this class has no useful truthiness behavior. If a file transfer fails, some exception will be raised, either an OSError or an error from within Paramiko.
- Parameters:
local_tmp_storage (String) – Path to store the zip file locally.
filename (String) – Zip filename on Slurm.
- Returns:
The result of the scp attempt.
- Return type:
TransferResult
- extract_data_location_from_log(slurm_job_id: str = None, logfile: str = None) str[source]
Read SLURM job logfile to find location of the data.
One of the parameters is required, either id or file.
- extract_job_id(result: Result) int[source]
Extract the Slurm job ID from the result of a command.
- Parameters:
result (Result) – The result of a command execution.
- Returns:
The Slurm job ID extracted from the result, or -1 if not found.
- Return type:
- extract_parts_from_url(input_url: str) Tuple[List[str], str][source]
Extract the repository and branch information from the input URL.
- Parameters:
input_url (str) – The input GitHub URL.
- Returns:
The list of url parts and the branch/version. If no branch is found, it will return “master”
- Return type:
- Raises:
ValueError – If the input URL is not a valid GitHub URL.
- classmethod from_config(configfile: str = '', init_slurm: bool = False, config_only: bool = False) SlurmClient[source]
Creates a new SlurmClient object using the parameters read from a configuration file (.ini).
- Defaults paths to look for config files are:
/etc/slurm-config.ini
/OMERO/slurm-config.ini
~/slurm-config.ini
Set
BIOMERO_SLURM_CONFIG_FILEto enable authoritative-file mode. In that mode only the configured file is read; default paths and an explicitconfigfileargument are intentionally ignored.Note that this is only for the SLURM-specific values that we added. Most configuration values are set via configuration mechanisms from Fabric library, like SSH settings being loaded from SSH config, /etc/fabric.yml or environment variables. See Fabric’s documentation for more info on configuration if needed.
- Parameters:
- Returns:
A new SlurmClient object.
- Return type:
- generate_slurm_job_for_workflow(workflow: str, substitutes: Dict[str, str], template: str = 'job_template.sh') str[source]
Generate a Slurm job script for a specific workflow.
- Parameters:
- Returns:
The generated Slurm job script as a string.
- Return type:
- generic_descriptor_from_github(workflow: str) Dict[source]
Pull the workflow descriptor from GitHub and convert to generic format.
- Parameters:
workflow (str) – Workflow name (looked up in
slurm_model_repos) or a direct GitHub repository URL.- Returns:
The descriptor in biomero-schema format.
- Return type:
Dict
- Raises:
ValueError – If no descriptor file is found or the URL is invalid.
- get_active_job_progress(slurm_job_id: str, pattern: str = '\\d+%', env: Dict[str, str] | None = None) Any[source]
Get the progress of an active Slurm job from its logfiles.
- Parameters:
- Returns:
The progress of the Slurm job according to the pattern, or None.
- Return type:
Any
- get_all_image_versions_and_data_files() Tuple[Dict[str, List[str]], List[str]][source]
Retrieve all available image versions and data files from the Slurm cluster.
- classmethod get_authoritative_config_path()[source]
Return the configured authoritative ini path, if enabled.
- get_cellpose_command(image_version: str, input_data: str, cp_model: str, nuc_channel: int, prob_threshold: float, cell_diameter: float, email: str | None = None, time: str | None = None, use_gpu: bool = True, model: str = 'cellpose') Tuple[str, Dict][source]
Return the command and environment dictionary to run a CellPose job on the Slurm workload manager. A specific example of using the generic ‘get_workflow_command’.
- Parameters:
image_version (str) – The version of the Singularity image to use.
input_data (str) – The name of the input data folder on the shared file system.
cp_model (str) – The name of the CellPose model to use.
nuc_channel (int) – The index of the nuclear channel.
prob_threshold (float) – The probability threshold for nuclei detection.
cell_diameter (float) – The expected cell diameter in pixels.
email (Optional[str]) – The email address to send notifications to. Defaults to None.
time (Optional[str]) – The maximum time for the job to run. Defaults to None.
use_gpu (bool) – Whether to use GPU for the CellPose job. Defaults to True.
model (str) – The name of the folder of the Docker image to use. Defaults to “cellpose”.
- Returns:
A tuple containing the Slurm sbatch command and the environment dictionary.
- Return type:
- classmethod get_config_paths(configfile: str = '') list[str][source]
Resolve config paths in effective read order.
BIOMERO_SLURM_CONFIG_FILEenables authoritative-file mode and replaces all default and caller-supplied config layers.
- classmethod get_config_write_path() str[source]
Resolve the writable admin overlay or authoritative ini path.
Used by the OMERO.biomero admin UI to know which file to save its settings to.
- get_conversion_command(data_path: str, config_file: str, source_format: str = 'zarr', target_format: str = 'tiff', submission_job_name: str | None = None) Tuple[str, Dict, str, str][source]
Generate Slurm conversion command and environment variables for data conversion.
- Parameters:
data_path (str) – Path to the data folder.
config_file (str) – Path to the configuration file.
source_format (str) – Source data format (default is ‘zarr’).
target_format (str) – Target data format (default is ‘tiff’).
submission_job_name (str, optional) – Slurm job name that identifies the submission of a tracked task (see
get_submission_job_name). Defaults toconversion.
- Returns:
A tuple containing the Slurm conversion command and the environment variables, followed by the converter image name and version.
- Return type:
Warning
The default implementation only supports conversion from ‘zarr’ to ‘tiff’. If using other source or target formats, users must implement and configure additional converters themselves.
- get_conversion_logfile_from_slurm(slurm_job_id: str, local_tmp_storage: str = '/tmp/', logfile: str = None) Tuple[str, str, Any][source]
Copy a conversion job’s log(s) to local storage as one combined file.
A conversion is submitted as a Slurm array job with
--output=omero-%A_%a.log, so it produces one log per array task (omero-<jobid>_1.log,omero-<jobid>_2.log, …). This reads all matching logs on the Slurm side and writes a single combined log file locally, so it can be attached to OMERO exactly like a workflow log – including when the conversion failed and the logs are the only clue.Unlike
get_logfile_from_slurm()(which sftp-copies a single named file) this resolves the array glob viacatand tolerates the case where no log files exist (writes an empty file rather than erroring).- Parameters:
- Returns:
- local directory, combined log file path, and
the raw
catResult.
- Return type:
- get_file_attachment_params(workflow: str) Dict[str, Dict[str, Any]][source]
Return only the file-attachment params for a workflow.
Thin filter over
get_workflow_parameters().
- get_image_pull_status() Dict[str, Any][source]
Return structured status for the most recent image submission.
- get_image_versions_and_data_files(model: str) Tuple[List[str], List[str]][source]
Retrieve the available image versions and input data files for a given model.
- Parameters:
model (str) – The name of the model to query for.
- Returns:
A tuple containing two lists: - The first list includes the available image versions,
sorted in descending order.
The second list includes the available data files.
- Return type:
- Raises:
ValueError – If the provided model is not found in the SlurmClient’s known model paths.
- get_job_params(overrides: Dict[str, Any] | None = None, *, excluded: Iterable[str] = (), base_params: Iterable[str] = ()) List[str][source]
Merge job resources, the default partition and global sbatch flags.
The one place that combines these sources, for workflow, conversion, image-pull and helper jobs. For each flag the first source that sets it wins:
base_params,overrides, then the default partition (--partitiononly, whenoverrideshas no partition), then the globalsbatch_*settings. The source of every flag is logged at DEBUG.- Parameters:
overrides (Optional[Dict[str, Any]]) – Job-specific resources by sbatch flag name without the dashes, e.g.
{'cpus-per-task': 4}. None and empty values are skipped.excluded (Iterable[str]) – Flag names (without
--) that globalsbatch_*settings must not add, because the caller owns them.base_params (Iterable[str]) –
--flag=valueparameters already chosen by a more specific source, such as per-workflow ones. Surrounding whitespace is stripped; they come first.
- Returns:
--flag=valueparameters, in the shell syntax theadministrator configured.
- Return type:
List[str]
- get_job_status_command(slurm_job_ids: List[int]) str[source]
Return the Slurm command to get the status of jobs with the given job IDs.
- get_jobs_info_command(start_time: str = None, end_time: str = 'now', columns: str = 'JobId', states: str = 'r,cd,f,to,rs,dl,nf') str[source]
Return the Slurm command to retrieve information about old jobs.
The command will be formatted with the specified start time, which is expected to be in the ISO format “YYYY-MM-DD”. The command will use the “sacct” tool to query the Slurm accounting database for jobs that started on or after the specified start time, and will output only the job IDs (-o JobId) without header or trailer lines (-n -X).
- Parameters:
start_time (str) – The start time from which to retrieve job information. Defaults to None, which resolves in priority order: class default (2023-01-01), then
sacct_start_timeconfig, thensacct_days_agoconfig (relative), then env varBIOMERO_SACCT_START_TIME, then env varBIOMERO_SACCT_START_DAYS_AGO(relative, highest priority).end_time (str) – The end time until which to retrieve job information. Defaults to “now”.
columns (str) – The columns to retrieve from the job information. Defaults to “JobId”. It is comma separated, e.g. “JobId,State”.
states (str) – The job states to include in the query. Defaults to “r,cd,f,to,rs,dl,nf”.
- Returns:
A string representing the Slurm command to retrieve information about old jobs.
- Return type:
- get_logfile_from_slurm(slurm_job_id: str, local_tmp_storage: str = '/tmp/', logfile: str = None) Tuple[str, str, Result][source]
Copy the logfile of the given SLURM job to the local server.
Note about (Transfer)Result:
Unlike similar classes such as invoke.runners.Result or fabric.runners.Result (which have a concept of “warn and return anyways on failure”) this class has no useful truthiness behavior. If a file transfer fails, some exception will be raised, either an OSError or an error from within Paramiko.
- Parameters:
- Returns:
directory, full path of the logfile, and TransferResult
- Return type:
Tuple
- get_recent_log_command(log_file: str, n: int = 10) str[source]
Get the command to retrieve the recent log entries from a specified log file.
- get_remote_shallower_receipts(workflow_id, canonical_inputs)[source]
Read trusted completed receipts from event-sourced helper tasks.
- get_shallower_job_params()[source]
Single-process CPU helper resources, also used for recovery jobs.
Global
sbatch_*flags that would break a single-process CPU job (SHALLOWER_EXCLUDED_FLAGS, GPU and per-task flags) are not added.
- static get_submission_job_name(task_id: Any) str[source]
Return the Slurm job name that identifies a task’s submission.
A job whose submission reply was lost is found again by this name.
- Parameters:
task_id (Any) – ID of the task.
- Returns:
The job name, for example
biomero-<task id>.- Return type:
- get_submission_state_prefix(task_id: Any) str[source]
Return the remote path prefix of a task’s submission receipts.
- Parameters:
task_id (Any) – ID of the task.
- Returns:
<slurm_data_path>/.biomero-recovery/<task id>.- Return type:
- get_task(task_id: Any) Task[source]
Read a task from the workflow tracker.
- Parameters:
task_id (Any) – ID of the task.
- Returns:
The task aggregate.
- Return type:
- get_unzip_command(zipfile: str, filter_filetypes: str = '*.zarr *.ome.zarr *.tiff *.tif') str[source]
Generate a command string for unzipping a data archive and creating required directories for Slurm jobs.
- Parameters:
zipfile (str) – The name of the zip archive file to extract. Without extension.
filter_filetypes (str, optional) – A space-separated string containing the file extensions to extract from the zip file. E.g. defaults to “*.zarr *.ome.zarr *.tiff *.tif”. Setting this argument to None will omit the file filter and extract all files.
- Returns:
The command to extract the specified filetypes from the zip file.
- Return type:
- get_update_slurm_scripts_command() str[source]
Generate the command to update the Git repository containing the Slurm scripts, if necessary.
- Returns:
A string containing the Git command to update the Slurm scripts.
- Return type:
- get_workflow(workflow_id: Any) WorkflowRun[source]
Read a workflow from the workflow tracker.
- Parameters:
workflow_id (Any) – ID of the workflow.
- Returns:
The workflow aggregate.
- Return type:
- get_workflow_command(workflow: str, workflow_version: str, input_data: str, email: str | None = None, time: str | None = None, submission_job_name: str | None = None, **kwargs) Tuple[str, Dict][source]
Generate the Slurm workflow command and environment variables.
- Parameters:
workflow (str) – The name of the workflow.
workflow_version (str) – The version of the workflow.
input_data (str) – The name of the input data folder containing the input image files.
email (str, optional) – The email address for job notifications. Defaults to None, which defaults to what is in the job script.
time (str, optional) – The time limit for the job in the format HH:MM:SS. Defaults to None, which defaults to what is in the job script.
submission_job_name (str, optional) – Slurm job name that identifies the submission of a tracked task (see
get_submission_job_name). Defaults to None, which keeps the job name of the job script.**kwargs – Additional keyword arguments for the workflow.
- Returns:
A tuple containing the Slurm workflow command and the environment variables.
- Return type:
Tuple[str, Dict]
- get_workflow_parameters(workflow: str) Dict[str, Dict[str, Any]][source]
Retrieve the parameters of a workflow.
- Parameters:
workflow (str) – The workflow for which to retrieve the parameters.
- Returns:
A dictionary containing the workflow parameters.
- Return type:
- Raises:
ValueError – If an error occurs while retrieving the workflow parameters.
- get_workflow_tasks(workflow_id: Any, *, task_name: str | None = None, input_data: str | None = None) List[Task][source]
Read the tasks of a workflow from the workflow tracker.
- Parameters:
- Returns:
- The matching task aggregates, in workflow order;
empty when workflow tracking is disabled.
- Return type:
List[Task]
- get_zip_command(data_location: str, filename: str) str[source]
Generate a command string for zipping the data on Slurm.
- init_workflows(force_update: bool = False)[source]
Retrieves the required info for the configured workflows from github. It will fill slurm_model_images with dockerhub links.
- Parameters:
force_update (bool) – Will overwrite already given paths in slurm_model_images
- initialize_analytics_system(reset_tables=False)[source]
Initialize the analytics system based on the analytics configuration passed to the constructor.
- Parameters:
reset_tables (bool) – If True, drops and recreates all views.
- list_active_jobs(env: Dict[str, str] | None = None) List[str][source]
Get a list of active jobs from SLURM.
- list_all_jobs(env: Dict[str, str] | None = None) List[str][source]
Get a list of all jobs from SLURM.
- list_available_converter_versions() Dict[source]
Note, assumes you use versioned converters. Will return a dict with a version of each converter on your Slurm. However, doesn’t work properly with unversioned sif.
- list_completed_jobs(env: Dict[str, str] | None = None) List[str][source]
Get a list of completed jobs from SLURM.
- classmethod load_config(configfile: str = '') ConfigParser[source]
Load BIOMERO configuration using the effective path policy.
Logs which files were read, and warns when authoritative-file mode ignores a caller-supplied
configfileor its file is missing.
- parse_docker_image_version(image: str) Tuple[str, str][source]
Parses the Docker image string to extract the image name and version tag.
- static positive_job_ids(slurm_job_ids: List) List[int][source]
Keep the entries that are valid Slurm job IDs: positive integers.
- Parameters:
slurm_job_ids (List) – Job IDs as numbers or strings; None and values that are not numbers (such as the -1 that
extract_job_idreturns for “not found”) are dropped.- Returns:
The valid job IDs, in the original order.
- Return type:
List[int]
- prepare_converters() List[Dict[str, str]][source]
Stage converter runtime files and return their image specifications.
- remove_submission_receipts(state_prefix: str) None[source]
Remove the receipt files of a submission whose outcome is recorded.
Call this once the event store holds the job ID (or the failure): the files are then no longer needed. A failure is only logged, as the files are harmless leftovers.
- Parameters:
state_prefix (str) – Remote path prefix of the receipt files; see
get_submission_state_prefix.
- run_commands(cmdlist: List[str], env: Dict[str, str] | None = None, sep: str = ' && ', log_stdout: bool = True, log_level: int = 20, **kwargs) Result[source]
Run a list of shell commands consecutively on the Slurm cluster, ensuring the success of each before proceeding to the next.
The environment variables can be set using the env argument. These commands retain the same session (environment variables etc.), unlike running them separately.
- Parameters:
cmdlist (List[str]) – A list of shell commands to run on Slurm.
env (Dict[str, str], optional) – Optional environment variables to set when running the command. Defaults to None.
sep (str, optional) – The separator used to concatenate the commands. Defaults to ‘ && ‘.
log_stdout (bool, optional) – Whether to log the stdout output. Defaults to True.
log_level (int, optional) – Log level of the command line, for long generated scripts. Defaults to INFO.
**kwargs – Additional keyword arguments.
- Returns:
The result of the last command in the list.
- Return type:
Result
- run_commands_read_only(commands, env=None, **kwargs)[source]
Read remote state while preserving the last known job status.
- run_commands_split_out(cmdlist: List[str], env: Dict[str, str] | None = None) List[str][source]
Run a list of shell commands consecutively and split the output of each command.
Each command in the list is executed with a separator in between that is unique and can be used to split the output of each command later. The separator used is specified by the _OUT_SEP attribute of the SlurmClient instance.
- Parameters:
- Returns:
A list of strings, where each string corresponds to the output of a single command in cmdlist split by the separator _OUT_SEP.
- Return type:
List[str]
- Raises:
SSHException – If any of the commands fail to execute successfully.
- run_conversion_workflow_job(folder_name: str, source_format: str = 'zarr', target_format: str = 'tiff', wf_id: UUID = None) SlurmJob[source]
Run the data conversion workflow on Slurm using the given data folder.
- Parameters:
- Returns:
the conversion job
- Return type:
Warning
The default implementation only supports conversion from ‘zarr’ to ‘tiff’. If using other source or target formats, users must implement and configure additional converters themselves.
- run_workflow(workflow_name: str, workflow_version: str, input_data: str, email: str | None = None, time: str | None = None, wf_id: UUID | None = None, output_settings: Dict | None = None, **kwargs) Tuple[Result, int, UUID, UUID][source]
Run a specified workflow on Slurm using the given parameters.
- Parameters:
workflow_name (str) – Name of the workflow to execute.
workflow_version (str) – Version of the workflow (image version on Slurm).
input_data (str) – Name of the input data folder containing input image files.
email (str, optional) – Email address for Slurm job notifications.
time (str, optional) – Time limit for the Slurm job in the format HH:MM:SS.
wf_id (UUID, optional) – Workflow ID for tracking purposes. If not provided, a new one is created.
**kwargs – Additional keyword arguments for the workflow.
- Returns:
A tuple containing the result of starting the workflow job, the Slurm job ID, the workflow ID, and the task ID. If the Slurm job ID could not be extracted, it returns -1 for the job ID.
- Return type:
Tuple[Result, int, UUID, UUID]
Note
The Slurm job ID is extracted from the result of the run_commands method. If track_workflows is enabled, workflow and task tracking is performed.
- run_workflow_job(workflow_name: str, workflow_version: str, input_data: str, email: str | None = None, time: str | None = None, wf_id: UUID | None = None, output_settings: Dict | None = None, **kwargs) SlurmJob[source]
Run a specified workflow on Slurm using the given parameters and return a SlurmJob instance.
- Parameters:
workflow_name (str) – Name of the workflow to execute.
workflow_version (str) – Version of the workflow (image version on Slurm).
input_data (str) – Name of the input data folder containing input image files.
email (str, optional) – Email address for Slurm job notifications.
time (str, optional) – Time limit for the Slurm job in the format HH:MM:SS.
wf_id (UUID, optional) – Workflow ID for tracking purposes. If not provided, a new one is created.
output_settings (dict, optional) – Selected output settings for results import.
**kwargs – Additional keyword arguments for the workflow.
- Returns:
A SlurmJob instance representing the started workflow job.
- Return type:
- setup_container_images(extra_image_specs: List[Dict[str, str]] = None) int | None[source]
Create workflow image directories and submit one combined array.
This is a submission of its own:
get_image_pull_statusreports only the most recent one, so pass the converter images asextra_image_specs(seeprepare_converters) to track them together, assetup_slurmdoes.
- setup_converters() int | None[source]
Stage converters and submit them through the shared image runner.
This is a submission of its own:
get_image_pull_statusreports only the most recent one.setup_slurmsubmits converters and workflow images together.- Returns:
- The Slurm array job ID, or None if nothing was
submitted to Slurm.
- Return type:
Optional[int]
- setup_directories()[source]
Creates necessary directories for Slurm operations.
This function creates directories for data storage, scripts, and workflows as specified in the SlurmClient object.
- Raises:
SSHException – If there is an issue executing directory creation commands.
- setup_job_scripts()[source]
Sets up job scripts for Slurm operations.
This function either clones a Git repository containing job scripts into the specified script path or generates scripts locally if no repository is provided.
- Raises:
SSHException – If there is an issue executing Git commands or generating scripts.
- shallow_results_on_slurm(data_path, workflow_id, canonical_inputs, *, heartbeat=None)[source]
Run/adopt optional CPU shallowing before result archiving.
The whole run is repeated within the SSH recovery window after a lost connection, so every step inside it must be safe to repeat: it adopts the recorded job or submits through
submit_job_once.heartbeatis a caller-owned no-argument callback invoked during job waits.
- str_to_class(module_name: str, class_name: str, *args, **kwargs)[source]
Return a class instance from a string reference.
- Parameters:
- Returns:
- An instance of the specified class, or None if the class or
module does not exist.
- Return type:
- submit_job_once(sbatch_command: str, state_prefix: str, *, job_name: str, env: Dict[str, str] | None = None, raise_on_rejection: bool = True, verify_command_unchanged: bool = True) Result[source]
Submit a Slurm job exactly once, even when the SSH reply is lost.
This is the one submit-exactly-once implementation, for workflows, conversions and helper jobs. It runs the submission under a remote lock with receipt files (see
remote_scripts.submit_once_script): asked again, it adopts the job already submitted, finds a job whose reply was lost by its name in Slurm, and never runssbatchagain while an earlier attempt may have created a job. The lock command isslurm_lock_cmd;sacctmust be available.- Parameters:
sbatch_command (str) – The submission command (any
sbatch…). It must usejob_nameas its Slurm job name.state_prefix (str) – Remote path prefix of the receipt files; see
get_submission_state_prefix.job_name (str) – The Slurm job name of this submission.
env (Optional[Dict[str, str]]) – Environment variables for the command.
raise_on_rejection (bool) – Raise
UnexpectedExitwhen sbatch refuses the job (default), and keep a receipt that repeats that answer. When False, return the failedResultand forget the attempt, so that a later call submits again.verify_command_unchanged (bool) – Stop when a recorded submission used a different command (default).
- Returns:
stdoutisSubmitted batch job <id>; seeextract_job_id. A refused job gives a failed Result whenraise_on_rejectionis False.
- Return type:
Result
- Raises:
UnexpectedExit – If sbatch refused the job, or the script failed.
ssh_recovery.SSHRecoveryTimeout – If the connection did not recover in time.
ssh_recovery.RemoteOperationStillPending – If the submission is still locked or its job is not visible in Slurm after the waiting time. Nothing is submitted again.
- transfer_data(local_path: str) Result[source]
Transfers a file or directory from the local machine to the remote Slurm cluster.
- Parameters:
local_path (str) – The local path to the file or directory to transfer.
- Returns:
The result of the file transfer operation.
- Return type:
Result
- unpack_data(zipfile: str, env: Dict[str, str] | None = None) Result[source]
Unpacks a zipped file on the remote Slurm cluster.
- update_slurm_scripts(generate_jobs: bool = False, env: Dict[str, str] | None = None) Result[source]
Updates the local copy of the Slurm job submission scripts.
This function pulls the latest version of the scripts from the Git repository and copies them to the slurm_script_path directory. Alternatively, it can generate scripts from a template. This is the default behavior if no Git repo is provided or can be forced via the generate_jobs parameter.
- Parameters:
- Returns:
The result of the command.
- Return type:
Result
- validate(validate_slurm_setup: bool = False)[source]
Validate the connection to the Slurm cluster by running a simple command.
- workflow_bilayers_folder_params_to_subs(descriptor: Dict) Dict[str, str][source]
Build INPARAMS and OUTPARAMS substitution strings for bilayers job templates.
Folder inputs (image/file/array/measurement/executable) are mapped to
$DATA_PATH/data/in. Outputs with a cli_tag and any parameter withoutput_dir_set=True(markedset-by-serverafter schema parsing) are mapped to$DATA_PATH/data/out.
- workflow_params_to_envvars(**kwargs) Dict[source]
Convert workflow parameters to environment variables.
- Parameters:
**kwargs – Additional keyword arguments for the workflow.
- Returns:
A dictionary containing the environment variables.
- Return type:
Dict
- workflow_params_to_subs(params) Dict[str, str][source]
Convert workflow parameters to substitution dictionary for job script.
- workflow_template_subs(descriptor: Dict) Dict[str, str][source]
Build shared-template substitutions for workflow family differences.
- class biomero.slurm_client.SlurmJob(submit_result: Result | None, job_id: int, wf_id: UUID, task_id: UUID, slurm_polling_interval: int = 10, log_file: str = None)[source]
Bases:
objectRepresents a job submitted to a Slurm cluster.
This class encapsulates information and methods related to managing a job submitted to a Slurm cluster. It provides functionality to monitor the job’s state, wait for completion, and perform cleanup operations.
- submit_result
The result of submitting the job.
- Type:
Result
- wf_id
The workflow ID associated with the job.
- Type:
UUID
- task_id
The task ID within the workflow.
- Type:
UUID
Example
# Submit some job with the SlurmClient submit_result, job_id, wf_id, task_id = slurmClient.run_workflow(
workflow_name, workflow_version, input_data, email, time, wf_id, **kwargs)
# Create a SlurmJob instance slurmJob = SlurmJob(submit_result, job_id, wf_id, task_id)
- if not slurmJob.ok:
logger.warning(f”Error with job: {slurmJob.get_error()}”)
- else:
- try:
# heartbeat is a no-argument callback supplied by the caller. slurmJob.wait_for_completion(slurmClient, heartbeat=heartbeat) if not slurmJob.completed():
raise Exception(f”Job is not completed: {slurmJob}”)
- else:
slurmJob.cleanup(slurmClient)
- except Exception as e:
logger.error(f” ERROR WITH JOB: {e}”) raise e
- SLURM_POLLING_INTERVAL = 10
- cleanup(slurmClient) Result[source]
Cleanup remaining log files.
- Parameters:
slurmClient – The Slurm client.
- Returns:
The result of the cleanup operation.
- Return type:
Result
- completed()[source]
Check if the Slurm job has completed successfully.
- Returns:
True if the job has completed; False otherwise.
- Return type:
- static ended_without_success(state: str | None) bool[source]
Tell whether a (raw) job state is final and not COMPLETED.
Failed, cancelled, timed-out, out-of-memory … jobs are never re-attached to on resume; a COMPLETED job may be, so that its outputs are processed instead of running the analysis again.
- classmethod from_job_id(job_id, wf_id=None, task_id=None, **kwargs)[source]
Monitor an already submitted job without submitting it again.
This process did not verify the submission, so the job is not
ok: monitoring it withwait_for_completionis the way to find out. Submission reconciliation remains the caller’s responsibility.
- get_error() str[source]
Get the error message associated with the Slurm job submission.
- Returns:
The error message, or an empty string if no error occurred.
- Return type:
- static state_name(state: str | None) str[source]
Return the bare Slurm state from a raw sacct/squeue state.
sacct may add a suffix (
CANCELLED+) or details (CANCELLED by 1000).
- wait_for_completion(slurmClient, omeroConn=None, *, heartbeat=None, track_progress=True, update_task=True, strict_status=False) str[source]
Wait for the Slurm job to reach completion, cancellation, failure, or timeout.
- Parameters:
slurmClient – The Slurm client.
omeroConn – Deprecated, kept for callers of BIOMERO 2.8.0 that pass the connection positionally. Its
keepAlive()is used as the heartbeat; passheartbeatinstead. Will be removed in a future major release.heartbeat – Optional no-argument callback, invoked before each poll. Return values are ignored; raise to abort monitoring. Exceptions propagate unchanged without marking the Slurm job failed. Takes precedence over
omeroConn.track_progress – Read analysis progress from job logs (default True).
update_task – Publish task status/progress (default True). Helpers whose success also requires report validation can disable this.
strict_status – Raise on unavailable status instead of recording a failure. This lets resumable callers preserve an existing job.
- Returns:
The final state of the Slurm job.
- Return type:
biomero.eventsourcing module
- class biomero.eventsourcing.NoOpWorkflowTracker[source]
Bases:
objectA no-operation workflow tracker that makes all method calls no-op.
All method calls to this class will return None and log the function name and its parameters for debugging purposes.
- class biomero.eventsourcing.ResultDict(result: Result)[source]
Bases:
dictA dictionary subclass that stores details from a Fabric Result object.
- Parameters:
result (Result) – The Fabric result object.
- class biomero.eventsourcing.Task(*args: Any, **kwargs: Any)[source]
Bases:
AggregateRepresents a task in a workflow as an aggregate in the domain model.
- workflow_id
The UUID of the associated workflow.
- Type:
UUID
- claimed_at
When that claim was made or last renewed.
- Type:
datetime
- class Created(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')
Bases:
Event,Created
- class Event(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')
Bases:
Event
- class JobIdAdded(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', job_id: str)[source]
Bases:
DecoratedFuncCaller,JobIdAdded
- class LauncherClaimed(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', owner: str, claimed_at: datetime.datetime)[source]
Bases:
DecoratedFuncCaller,LauncherClaimed
- class LauncherReleased(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')[source]
Bases:
DecoratedFuncCaller,LauncherReleased
- class ProgressUpdated(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', progress: str)[source]
Bases:
DecoratedFuncCaller,ProgressUpdated
- class ResultAdded(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', result: biomero.eventsourcing.ResultDict)[source]
Bases:
DecoratedFuncCaller,ResultAdded
- class StatusUpdated(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', status: str)[source]
Bases:
DecoratedFuncCaller,StatusUpdated
- class StorageProvenanceRecorded(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')
Bases:
DecoratedFuncCaller,Event
- class TaskCompleted(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', result: str)[source]
Bases:
DecoratedFuncCaller,TaskCompleted
- class TaskCreated(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', originator_topic: 'str', workflow_id: uuid.UUID, task_name: str, task_version: str, input_data: Dict[str, Any], params: Dict[str, Any])[source]
Bases:
TaskCreated,Event
- class TaskFailed(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', error_message: str)[source]
Bases:
DecoratedFuncCaller,TaskFailed
- class TaskStarted(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')[source]
Bases:
DecoratedFuncCaller,TaskStarted
- exception biomero.eventsourcing.WorkflowCancelled[source]
Bases:
WorkflowInterruptedA workflow was asked to cancel: stop, cancel its jobs, fail it.
- exception biomero.eventsourcing.WorkflowInterrupted[source]
Bases:
ExceptionWhoever runs a workflow must stop now, between its steps.
Deliberately not an
InterruptedError: that is anOSError, whichexcept OSErrorhandlers and the SSH recovery classifier would catch. Stage handlers let it pass; subclasses say why the run stopped.
- class biomero.eventsourcing.WorkflowRun(*args: Any, **kwargs: Any)[source]
Bases:
AggregateRepresents a workflow run as an aggregate in the domain model.
- class CancelRequested(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', reason: str)[source]
Bases:
DecoratedFuncCaller,CancelRequested
- class CanonicalInputsRecorded(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', export_task_id: uuid.UUID, canonical_inputs: List[Dict[str, Any]])[source]
Bases:
DecoratedFuncCaller,CanonicalInputsRecorded
- class Created(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')
Bases:
Event,Created
- class Event(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')
Bases:
Event
- class TaskAdded(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', task_id: uuid.UUID)[source]
Bases:
DecoratedFuncCaller,TaskAdded
- class WorkflowCompleted(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')[source]
Bases:
DecoratedFuncCaller,WorkflowCompleted
- class WorkflowFailed(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', error_message: str)[source]
Bases:
DecoratedFuncCaller,WorkflowFailed
- class WorkflowInitiated(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', originator_topic: 'str', name: str, description: str, user: int, group: int)[source]
Bases:
WorkflowInitiated,Event
- class WorkflowStarted(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')[source]
Bases:
DecoratedFuncCaller,WorkflowStarted
- complete_workflow() bool[source]
Complete the workflow, unless it already reached a final state.
The refusal is not part of the events, so streams that already contain two final events still replay; only new transitions are refused.
- Returns:
- False when the workflow was already final and nothing
was recorded.
- Return type:
- class biomero.eventsourcing.WorkflowTracker(env: Mapping[str, str] | None = None)[source]
Bases:
ApplicationApplication service class for managing workflow and task lifecycle operations.
- add_job_id(task_id, slurm_job_id)[source]
Adds a Slurm job ID to the task with the given UUID.
- Parameters:
task_id (UUID) – The UUID of the task.
slurm_job_id (str) – The Slurm job ID to associate with the task.
- add_launcher_task(workflow_id: UUID, task_name: str, task_version: str, input_data: Dict[str, Any], kwargs: Dict[str, Any]) UUID[source]
Adds the launcher task that queues a workflow for a detached supervisor: an ordinary task of a launching script, marked as launcher.
What goes into
kwargsis up to the caller (the script knows what its run needs); this only adds the marker, with the script version as its value, to a copy of it.- Parameters:
- Returns:
The UUID of the launcher task.
- Return type:
UUID
- Raises:
ValueError – If the task name is not a launching script.
- add_result(task_id, result)[source]
Adds a result to the task with the given UUID.
- Parameters:
task_id (UUID) – The UUID of the task.
result (Result) – The Fabric result object to add to the task.
- add_task_to_workflow(workflow_id: UUID, task_name: str, task_version: str, input_data: Dict[str, Any], kwargs: Dict[str, Any]) UUID[source]
Adds a task to the specified workflow.
- Parameters:
- Returns:
The UUID of the newly added task.
- Return type:
UUID
- claim_launcher_task(task_id: UUID, owner: str, lease_seconds: float = 300) bool[source]
Claims a launcher task for a supervisor, atomically.
This is a compare-and-set on the task’s event stream: the claim is appended as the next event of the task, and the event store accepts only one event per position. When two supervisors read the same task and both try to claim it, one of them loses and gets False.
A claim is valid for
lease_seconds. The owner renews it by claiming again; a claim that was not renewed (for example because the supervisor crashed) can be taken over by any other owner. Renew well within the lease (the processor renews three times per lease). The lease compares the claim’s timestamp with this process’s clock, so supervisors must have clocks that agree to well within the lease; the event-store position, not the clock, is what keeps two claims apart.- Parameters:
- Returns:
True when the caller now holds the claim.
- Return type:
- Raises:
ValueError – If the task is not a launcher task.
- commit_open_transaction() None[source]
Commits what was saved on a datastore that leaves the transaction to its caller (the scoped-session store); other stores commit on save.
Use this after
save()for aggregates that are not written through one of the tracker’s own methods.
- complete_task(task_id: UUID, message: str)[source]
Marks the task with the given UUID as completed with a result message.
- Parameters:
task_id (UUID) – The UUID of the task to complete.
message (str) – The result message of the task.
- complete_workflow(workflow_id: UUID)[source]
Marks the workflow with the given UUID as completed.
- Parameters:
workflow_id (UUID) – The UUID of the workflow to complete.
- fail_task(task_id: UUID, error_message: str)[source]
Marks the task with the given UUID as failed with an error message.
- Parameters:
task_id (UUID) – The UUID of the task to fail.
error_message (str) – The error message describing the failure.
- fail_workflow(workflow_id: UUID, error_message: str)[source]
Marks the workflow with the given UUID as failed with an error message.
- Parameters:
workflow_id (UUID) – The UUID of the workflow to fail.
error_message (str) – The error message describing the failure.
- find_launcher_task(workflow_id: UUID) Task | None[source]
Finds the launcher task that queued a workflow for a supervisor.
- get_canonical_input_manifest(workflow_id: UUID) CanonicalInputManifest[source]
Returns the validated, JSON-serializable recovery manifest.
- get_canonical_inputs(workflow_id: UUID) Dict[str, Any][source]
Returns the canonical input snapshot recorded for a workflow.
- initiate_workflow(name: str, description: str, user: int, group: int) UUID[source]
Initiates a new workflow.
- is_workflow_cancel_requested(workflow_id: UUID) bool[source]
Whether a cancel was requested for the workflow.
- Parameters:
workflow_id (UUID) – The workflow to check.
- Returns:
True once request_workflow_cancel() was called for it.
- Return type:
- is_workflow_finished(workflow_id: UUID) bool[source]
Whether the workflow already completed or failed.
- Parameters:
workflow_id (UUID) – The workflow to check.
- Returns:
True once the workflow reached a final state.
- Return type:
- iter_workflow_tasks(workflow_id: UUID) Iterator[Task][source]
Yields the tasks of a workflow, in the order they were added.
Read errors are raised, not hidden: an unreadable history is not an empty one.
- Parameters:
workflow_id (UUID) – The UUID of the workflow.
- Yields:
Task – One task aggregate at a time.
- name = 'WorkflowTracker'
- raise_if_cancel_requested(workflow_id: UUID) None[source]
Stops the caller when a cancel was requested for the workflow. Call it between the steps of a workflow run.
- Parameters:
workflow_id (UUID) – The workflow that is being run.
- Raises:
WorkflowCancelled – When request_workflow_cancel() was called.
- record_canonical_inputs(workflow_id: UUID, export_task_id: UUID, canonical_inputs: Sequence[CanonicalInput | Mapping[str, Any]]) None[source]
Records the exact canonical input generations used by a workflow.
- record_storage_provenance(task_id, target_key, evidence)[source]
Persist observed storage provenance for an opaque result target.
- release_database_connections() None[source]
Gives this tracker’s database connections back, for a thread that is done with its own tracker.
- release_launcher_task(task_id: UUID, owner: str) bool[source]
Gives a claim up, so another supervisor can take the run over at once instead of after the lease has expired.
- request_workflow_cancel(workflow_id: UUID, reason: str) None[source]
Records that a workflow must be cancelled. Whoever executes the workflow (the inline script or the detached supervisor) reads this and stops; asking again changes nothing.
- Parameters:
workflow_id (UUID) – The workflow to cancel.
reason (str) – Why, for the record.
- start_task(task_id: UUID)[source]
Starts the task with the given UUID.
- Parameters:
task_id (UUID) – The UUID of the task to start.
- start_workflow(workflow_id: UUID)[source]
Starts the workflow with the given UUID.
- Parameters:
workflow_id (UUID) – The UUID of the workflow to start.
- biomero.eventsourcing.is_launcher_task(task) bool[source]
Whether a task is a launcher queued for a detached supervisor.
Works on a Task aggregate and on a Task.TaskCreated event alike, so every reader (supervisor, views, provenance) applies the same rule.
- Parameters:
task – Anything with
task_nameandparams.- Returns:
True for a launching script’s task that carries the marker.
- Return type:
biomero.views module
- class biomero.views.JobAccounting(*args, **kwargs)[source]
Bases:
ProcessApplication- get_jobs(user=None, group=None)[source]
Retrieve jobs for a specific user and/or group.
Parameters: - user (int, optional): The user ID to filter by. - group (int, optional): The group ID to filter by.
Returns: - Dictionary of user IDs to lists of job IDs if no user is specified. - Dictionary with a single user ID key and a list of job IDs if user is specified.
Raises: - ValueError: If neither user nor group is provided.
- get_task_id(job_id)[source]
Retrieve the task ID associated with a given job ID.
Parameters: - job_id (int): The job ID (slurm_job_id) to look up.
Returns: - UUID: The task ID associated with the job ID, or None if not found.
- name = 'JobAccounting'
- policy(domain_event, process_event)[source]
- policy(domain_event: WorkflowInitiated, process_event)
- policy(domain_event: TaskAdded, process_event)
- policy(domain_event: JobIdAdded, process_event)
Default policy
- class biomero.views.JobProgress(*args, **kwargs)[source]
Bases:
ProcessApplication- name = 'JobProgress'
- policy(domain_event, process_event)[source]
- policy(domain_event: JobIdAdded, process_event)
- policy(domain_event: StatusUpdated, process_event)
- policy(domain_event: ProgressUpdated, process_event)
Default policy
- class biomero.views.WorkflowAnalytics(*args, **kwargs)[source]
Bases:
ProcessApplication- get_average_task_duration(user=None, group=None)[source]
Retrieve the average task duration grouped by task name and version.
Parameters: - user (int, optional): The user ID to filter by. - group (int, optional): The group ID to filter by.
Returns: - Dictionary of task names and versions to average duration (in seconds).
- get_task_counts(user=None, group=None)[source]
Retrieve task execution counts grouped by task name and version.
Parameters: - user (int, optional): The user ID to filter by. - group (int, optional): The group ID to filter by.
Returns: - Dictionary of task names and versions to counts.
- get_task_failures(user=None, group=None)[source]
Retrieve tasks that failed, grouped by task name and version.
Parameters: - user (int, optional): The user ID to filter by. - group (int, optional): The group ID to filter by.
Returns: - Dictionary of task names and versions to lists of failure reasons.
- get_task_usage_over_time(task_name, user=None, group=None)[source]
Retrieve task usage over time for a specific task.
Parameters: - task_name (str): The name of the task to filter by. - user (int, optional): The user ID to filter by. - group (int, optional): The group ID to filter by.
Returns: - Dictionary mapping date to the count of task executions on that date.
- name = 'WorkflowAnalytics'
- policy(domain_event, process_event)[source]
- policy(domain_event: WorkflowInitiated, process_event)
- policy(domain_event: TaskAdded, process_event)
- policy(domain_event: TaskCreated, process_event)
- policy(domain_event: TaskStarted, process_event)
- policy(domain_event: StatusUpdated, process_event)
- policy(domain_event: TaskCompleted, process_event)
- policy(domain_event: TaskFailed, process_event)
Default policy
- class biomero.views.WorkflowProgress(*args, **kwargs)[source]
Bases:
ProcessApplication- name = 'WorkflowProgress'
- policy(domain_event, process_event)[source]
- policy(domain_event: WorkflowInitiated, process_event)
- policy(domain_event: WorkflowCompleted, process_event)
- policy(domain_event: WorkflowFailed, process_event)
- policy(domain_event: TaskAdded, process_event)
- policy(domain_event: TaskCreated, process_event)
- policy(domain_event: TaskStarted, process_event)
- policy(domain_event: StatusUpdated, process_event)
- policy(domain_event: ProgressUpdated, process_event)
Default policy
biomero.provenance module
Versioned OMERO key/value views of immutable workflow history.
This module neither writes events nor changes OMERO objects. Full CSV export is deliberately independent of this searchable, selectively reduced view.
- class biomero.provenance.MetadataChange(before: biomero.provenance.MetadataAnnotation, after: biomero.provenance.MetadataAnnotation | None)[source]
Bases:
object
- biomero.provenance.plan_metadata_refresh(tracker, workflow_id, annotations, *, view_version='v0', target_key=None, refresh_storage=False)[source]
Plan a snapshot-preserving update. None means unlink, not global delete.
Unknown namespaces and extra keys are preserved. Missing task snapshots, duplicate identities and changed namespaces fail closed. Large fields that were already replaced by CSV references remain reduced.
Explicit storage repair may advance the import-task snapshot to a version carrying newly recorded evidence for target_key. Other snapshots stay pinned. Existing, different storage evidence is never silently replaced.
- biomero.provenance.render_workflow_metadata(tracker, workflow_id, *, view_version='v0', aggregate_versions=None, revision_fields=True, target_key=None)[source]
Return ordered namespace/value pairs without writing to any datastore.
v0is the only supported view and retains legacy task/job fields, including job command, environment and result-message fields. It omits detached coordination tasks and duplicated output settings. Scientific false/zero values are retained.Versionstill means the software version.An explicit
aggregate_versionsmapping pins the workflow and every retained task independently. Missing versions fail instead of mixing a historical workflow with current task state.
- biomero.provenance.resolve_metadata_versions(tracker, workflow_id, annotations)[source]
Recover exact aggregate versions from existing KV snapshots.
Legacy maps have no revision number: require a unique Modified_On match. Job maps inherit the paired task snapshot, never the current task version. Missing/inconsistent snapshots are errors; callers must not guess.
biomero.detached module
The detached-mode setting, and aliases for names that moved.
A BIOMERO workflow run outlives the OMERO session that asks for it, so a script can queue the run in a launcher task and a supervisor (the OMERO processor in NL-BIOMERO) executes it. Core only provides the mechanisms:
the launcher marker and rule:
constants.LAUNCHER_MARKER,WorkflowTracker.add_launcher_taskandeventsourcing.is_launcher_task;task lookup and the atomic claim:
WorkflowTracker.find_launcher_task,WorkflowTracker.claim_launcher_taskandWorkflowTracker.release_launcher_task;cancellation:
WorkflowTracker.request_workflow_cancelandSlurmClient.cancel_slurm_jobs.
The scripts decide what to record in a launcher task and how to resume a run; the supervisor decides which runs to execute. This module holds the one reader of the setting that switches the feature on, which the scripts and the supervisor all need, plus aliases that keep the names of the 2.9 betas working. The aliases are deprecated: use the names above.
- biomero.detached.detached_mode_enabled() bool[source]
Whether workflow scripts should queue runs instead of executing them.
Opt-in through the BIOMERO_DETACHED_WORKFLOWS environment variable of the OMERO processor running the script, because it requires a supervisor to be present: without one, a queued run would never be executed. The variable is declared in constants.slurm_env so that the processor forwards it to the script subprocesses it starts, which is where this is read. This is the only reader of the variable: callers use this function.
- Returns:
True when the variable has one of constants.TRUTHY_VALUES.
- Return type:
biomero.maintenance module
Durable metadata-maintenance requests, separate from analysis workflows.
Only plain request options and compact outcomes are persisted. The processor owns execution; the scripts layer owns all external annotation operations.
Why this is in core and not in the processor or the scripts: a request is an
aggregate in the WorkflowTracker event store, next to the workflow aggregates.
Every projection of that store (biomero.views) resolves the class of each
event it reads from the event’s stored topic, and the topic is the import path
of the class: biomero.maintenance:MetadataRefresh.Started and so on. A
class that only the processor or a script can import would make every other
process that replays the store fail on these events, and moving the class would
orphan the requests already stored. The request lifecycle (this aggregate and
its notification scan) therefore stays here; running a request does not.
- class biomero.maintenance.MetadataRefresh(*args: Any, **kwargs: Any)[source]
Bases:
AggregateA resumable maintenance request in the WorkflowTracker event store.
The public methods guard the lifecycle and raise ValueError for a transition that cannot happen. The guards are not part of the events, so a stream written before they existed still replays.
- class Created(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime', originator_topic: 'str')
Bases:
Created,Event
- class Event(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')
Bases:
Event
- class Finished(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')
Bases:
DecoratedFuncCaller,Event
- class Progress(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')
Bases:
DecoratedFuncCaller,Event
- class Started(self, originator_id: 'UUID', originator_version: 'int', timestamp: 'datetime')
Bases:
DecoratedFuncCaller,Event
- biomero.maintenance.metadata_refresh_statuses(tracker, recent: int = 5) List[Dict][source]
Plain snapshots of all active and the most recent finished requests.
This replays the request notifications from the start on every call, which is meant for an occasional administrator status check.
- Parameters:
tracker (WorkflowTracker) – Tracker whose event store holds requests.
recent (int, optional) – How many finished requests to include.
- Returns:
One dict per request, newest first.
- Return type:
- biomero.maintenance.pending_metadata_refreshes(tracker, start: int = 1, pending: Set[UUID] | None = None) Tuple[int, Set[UUID]][source]
Catch up on request notifications; a RUNNING request stays pending.
A request that was RUNNING when its supervisor stopped has no Finished event, so it is pending again after a restart and gets resumed.
- Parameters:
tracker (WorkflowTracker) – Tracker whose notification log to read.
start (int, optional) – Notification cursor from a previous call.
pending (set, optional) – Pending request IDs from a previous call.
- Returns:
- The cursor to continue from, and the IDs of the requests that
are queued or running.
- Return type:
- biomero.maintenance.queue_metadata_refresh(tracker, user: int, group: int, options: dict) UUID[source]
Persist the handoff before the requesting script closes its session.
- Parameters:
tracker (WorkflowTracker) – Tracker whose event store holds requests.
user (int) – OMERO user ID of the administrator who asked.
group (int) – OMERO group ID to run in.
options (dict) – Plain request options for the refresh.
- Returns:
The request ID.
- Return type:
UUID
biomero.remote_shallower module
Optional CPU result shallowing before result archiving.
SlurmClient owns remote execution, image acquisition, job submission and scheduling policy; SlurmJob owns monitoring. This module coordinates the shallower’s manifest, durable submission records, recovery command and receipt validation.
- class biomero.remote_shallower.HelperJob(task_id: Any, task: Task, image: str, sif_path: str, output_path: str, manifest_path: str, state_dir: str)[source]
The task, image and remote paths of one helper (shallower) job.
taskis the snapshot read when the job was started or resumed; read the task again withtask_idwhere recorded job IDs may have changed.- task_id: Any
Alias for field number 0
- class biomero.remote_shallower.HelperSettings(contract_version: int = 1, manifest_schema: int = 2, polling_interval: int = 15, lock_wait_seconds: int = 30)[source]
Values the entry point can change, threaded to the steps that use them.
Each value defaults to the module constant of the same meaning.
- biomero.remote_shallower.build_helper_command(slurm_client: SlurmClient, output_path: str, sif_path: str, manifest_path: str, task_id: str, *, recovery: bool = False, image: str | None = None, contract_version: int = 1) str[source]
Build the shallowing or recovery job using one helper resource policy.
Paths refer to the remote filesystem. The job is submitted through the SlurmClient, so the configured site defaults apply.
- Parameters:
slurm_client (SlurmClient) – The Slurm client holding the configuration.
output_path (str) – Result directory to shallow.
sif_path (str) – Path of the helper image.
manifest_path (str) – Path of the canonical input manifest.
task_id (str) – ID of the helper task.
recovery (bool) – Build the recovery command instead of the shallowing command (default False).
image (Optional[str]) – Image reference recorded for the task; defaults to the configured
remote_shallower_image.contract_version (int) – Runtime contract the helper must follow.
- Returns:
The
sbatchcommand.- Return type:
- Raises:
ValueError – If the configured worker count is not positive.
- biomero.remote_shallower.completed_receipts(slurm_client: SlurmClient, workflow_id: Any, canonical: CanonicalInputManifest) Tuple[RemoteShallowReceipt, ...][source]
Read persisted helper receipts without contacting the cluster.
- Parameters:
slurm_client (SlurmClient) – The Slurm client with the workflow tracker.
workflow_id (Any) – ID of the workflow.
canonical (CanonicalInputManifest) – The canonical input manifest the receipts must match.
- Returns:
- The receipts of completed helper
tasks; empty when remote shallowing or workflow tracking is disabled.
- Return type:
Tuple[RemoteShallowReceipt, …]
- biomero.remote_shallower.helper_job_name(task_id: Any, *, recovery: bool = False) str[source]
Keep submission reconciliation specific to one task and operation.
- biomero.remote_shallower.image_spec(slurm_client: SlurmClient, *, image: str | None = None) Dict[str, str][source]
Describe the configured helper image for SlurmClient image acquisition.
- Parameters:
slurm_client (SlurmClient) – The Slurm client holding the configuration.
image (Optional[str]) – Image reference to describe instead of the configured
remote_shallower_image.
- Returns:
The image specification for image acquisition.
- Return type:
- Raises:
ValueError – If no image is configured, or its digest or version is missing or invalid.
- biomero.remote_shallower.installed_tool_version(slurm_client: SlurmClient, sif_path: str) str[source]
Read the installed helper’s version without executing its payload.
A floating image tag is not a tool version. Persist the OCI version label before submission so receipt validation and recovery use a concrete value.
- Parameters:
slurm_client (SlurmClient) – The Slurm client used to run commands.
sif_path (str) – Remote path of the installed helper image.
- Returns:
The installed tool version.
- Return type:
- biomero.remote_shallower.parse_batch_report(slurm_client: SlurmClient, report_json: str, canonical: CanonicalInputManifest, *, task: Task | None = None) ShallowBatchReport[source]
Parse a helper batch report and check its input, image and tool version.
When a task is supplied, its recorded image/version and submission own the report; current deployment defaults must not invalidate historical results. Import the optional schema dependency only when shallowing is used.
- Parameters:
slurm_client (SlurmClient) – The Slurm client holding the configuration.
report_json (str) – The JSON batch report written by the helper.
canonical (CanonicalInputManifest) – The canonical input manifest the report must match.
task (Optional[Task]) – The recorded helper task owning the report.
- Returns:
The parsed batch report.
- Return type:
ShallowBatchReport
- Raises:
ValueError – If the report does not match the configuration, input, task or job.
- biomero.remote_shallower.publish_or_verify_manifest(slurm_client: SlurmClient, manifest_path: str, canonical: CanonicalInputManifest, *, submitted: bool, lock_wait_seconds: int = 30) None[source]
Verify an existing manifest or publish a new one without overwriting.
A sibling temporary file is fully uploaded before an atomic hard-link publishes it under a lock. Readers never see a partly uploaded manifest. Existing content is verified, not replaced on resume.
- Parameters:
slurm_client (SlurmClient) – The Slurm client used to run commands.
manifest_path (str) – Remote path of the canonical input manifest.
canonical (CanonicalInputManifest) – The canonical input manifest to publish or verify.
submitted (bool) – Whether the helper job was already submitted, which makes a missing manifest an error.
lock_wait_seconds (int) – How long to wait for the publication lock.
- Raises:
RuntimeError – If the manifest cannot be read or published, or is missing for a submitted job.
ValueError – If an existing manifest differs from the workflow input.
- biomero.remote_shallower.sha256_of_json(payload: Any) str[source]
Fingerprint JSON content independently of key order and whitespace.
- Parameters:
payload (Any) – A JSON-serializable value.
- Returns:
The hex SHA-256 of the canonical JSON encoding.
- Return type:
- biomero.remote_shallower.shallow_workflow_results(slurm_client: SlurmClient, data_path: str, workflow_id: Any, canonical: CanonicalInputManifest, heartbeat: Callable[[], None] | None = None, *, contract_version: int = 1, manifest_schema: int = 2, polling_interval: int = 15, lock_wait_seconds: int = 30) ShallowBatchReport | None[source]
Shallow the workflow results on the cluster, or resume that work.
Only initialization acquires container images. A rejected shallowing submission returns an empty-receipt report so the caller can retain full results. Callers must not archive potentially incomplete output.
- Parameters:
slurm_client (SlurmClient) – The Slurm client with the workflow tracker.
data_path (str) – Remote data folder of the workflow results.
workflow_id (Any) – ID of the workflow.
canonical (CanonicalInputManifest) – The canonical input manifest of the workflow.
heartbeat (Optional[Callable[[], None]]) – Callback invoked during job waits.
contract_version (int) – Runtime contract the helper must follow.
manifest_schema (int) – Shallow manifest schema the helper must emit.
polling_interval (int) – Seconds between job status polls.
lock_wait_seconds (int) – How long to wait for the manifest lock.
- Returns:
- The validated report, or None when
shallowing is disabled or inapplicable.
- Return type:
Optional[ShallowBatchReport]
- Raises:
RuntimeError – If the image is missing, the submission or recovery is unresolved or failed, or the report is missing.
ValueError – If the installed tool or the report is invalid.
- biomero.remote_shallower.validate_installed_tool(slurm_client: SlurmClient, sif_path: str, *, expected_version: str | None = None, runtime_contract: int = 1, manifest_schema: int = 2) str[source]
Fail closed unless the installed SIF satisfies this runtime contract.
- Parameters:
slurm_client (SlurmClient) – The Slurm client used to run commands.
sif_path (str) – Remote path of the installed helper image.
expected_version (Optional[str]) – Version the image must have; defaults to the configured
remote_shallower_version.runtime_contract (int) – Runtime contract the image must support.
manifest_schema (int) – Shallow manifest schema the image must emit.
- Returns:
The installed tool version.
- Return type:
- Raises:
ValueError – If the labels or the configured version are invalid.
RuntimeError – If the version, capability schema, runtime contract or manifest schema is not supported.
- biomero.remote_shallower.verify_task_canonical_inputs(task: Task, canonical: CanonicalInputManifest) None[source]
Raise unless the canonical inputs equal those recorded on the task.
- Parameters:
task (Any) – The recorded helper task.
canonical (Any) – The canonical input manifest of the workflow.
- Raises:
ValueError – If the task recorded a different canonical manifest.
- biomero.remote_shallower.wait_for_helper_job(slurm_client: SlurmClient, job_id: int, heartbeat: Callable[[], None] | None = None, polling_interval: int = 15) str[source]
Monitor an adopted job without analysis-log or task-status updates.
The helper task is completed after report validation, not merely because its Slurm process exited successfully.
- Parameters:
slurm_client (SlurmClient) – The Slurm client used to poll the job.
job_id (int) – The Slurm job ID.
heartbeat (Optional[Callable[[], None]]) – Callback invoked before each poll.
polling_interval (int) – Seconds between status polls.
- Returns:
The final state of the Slurm job.
- Return type:
biomero.ssh_recovery module
Bounded recovery from interrupted SSH connections.
An SSH connection to the cluster can drop while a Slurm job keeps running.
This module retries an operation that is safe to repeat, within a time window
(ssh_recovery_timeout), and stops with a clear error when the window ends.
A window of 0 means no retries: the same code runs once and raises the
original error.
Only transport loss is retried: never authentication, never a command that
failed on the cluster, and never an arbitrary command. The caller decides
which operations are safe to repeat and wraps them in retry. The Slurm
side (never submitting twice) lives in SlurmClient and remote_scripts.
- exception biomero.ssh_recovery.IncompleteTransfer[source]
Bases:
ConnectionErrorA file transfer ended with a different size than its source.
- class biomero.ssh_recovery.OutageWindow(timeout: float, outage_deadline: float | None = None, pending_deadline: float | None = None, delay: float = 1)[source]
Bases:
objectThe time budget of one
retrycall.A deadline starts at the first failure of its kind and is never moved by anything else, so that repeated failures cannot extend a call forever. A new
retrycall (the next poll, the next transfer) gets a new window.- pending_deadline
End of the window in which a healthy remote operation is awaited.
- Type:
Optional[float]
- next_pause(seconds_left: float) float[source]
Return the pause before the next attempt and grow the delay.
- seconds_left(error: BaseException, now: float) float[source]
Seconds left in the window of this kind of failure.
- start_if_new(error: BaseException, now: float) None[source]
Open the window of this kind of failure at its first occurrence.
- exception biomero.ssh_recovery.ReadOnlyCommandTimeout[source]
Bases:
TimeoutErrorA short read-only command did not answer within its bound.
- exception biomero.ssh_recovery.RecoveryPending[source]
Bases:
ExceptionA durable remote operation is still locked or not yet visible.
The connection works; the operation may still be running remotely. It is asked again after a pause, and never resubmitted.
- class biomero.ssh_recovery.RecoveryState(timeout: float, windows: ~typing.List[~biomero.ssh_recovery.OutageWindow] = <factory>, heartbeats: ~typing.List[~typing.Callable[[], None]] = <factory>, heartbeat_error: Exception | None = None)[source]
Bases:
objectWhat nested operations of one client share while recovering.
- windows
The windows of the active
retrycalls, outermost first.- Type:
List[OutageWindow]
- heartbeats
Caller callbacks that run during waits (for example an OMERO session keepalive).
- Type:
List[Callable[[], None]]
- heartbeat_error
An error raised by a callback; it is the caller’s, so it is never retried.
- Type:
Optional[Exception]
- pulse() None[source]
Run the caller callbacks once each.
- Raises:
Exception – Whatever a callback raised; it is remembered so that it is not mistaken for an SSH error.
- static raise_if_cancelled(cancel: Any | None, description: str) None[source]
Raise
SSHRecoveryCancelledwhen the caller’s event is set.
- exception biomero.ssh_recovery.RemoteOperationStillPending[source]
Bases:
RuntimeErrorA remote operation was still running when its waiting time ended.
The SSH connection is healthy and nothing was repeated: the operation continues on the cluster and can be asked again later.
- exception biomero.ssh_recovery.SSHRecoveryCancelled[source]
Bases:
InterruptedErrorThe caller cancelled while waiting for connectivity.
- exception biomero.ssh_recovery.SSHRecoveryTimeout[source]
Bases:
ConnectionErrorConnectivity did not recover within the configured time window.
- biomero.ssh_recovery.atomic_get(connection: Connection, remote: str, directory: str) Result[source]
Download a file so that the local name never shows a partial file.
The data goes to a temporary local file, is checked against the remote file (unchanged and complete), and then replaces the local file. An earlier complete local file stays available until then.
- Parameters:
- Returns:
The result, with
localset to the final path.- Return type:
TransferResult
- Raises:
IncompleteTransfer – If the remote file changed or the download is incomplete (retried).
- biomero.ssh_recovery.atomic_put(connection: Connection, local: str | StringIO | BytesIO, remote: str, partial_suffix: str = '.biomero-partial') Result[source]
Upload a file so that the remote name never shows a partial file.
The data goes to
<remote><partial_suffix>first, is checked for its size, and is renamed toremote. An interrupted upload restarts from the beginning. A previous remote file keeps its permission bits. Concurrent uploads to one remote name are not coordinated: the last rename wins.- Parameters:
connection (Connection) – The
SlurmClient.local (Union[str, io.StringIO, io.BytesIO]) – A local path or an in-memory source.
remote (str) – The final remote path.
partial_suffix (str) – Suffix of the temporary remote name.
- Returns:
The result, with
remoteset to the final path.- Return type:
TransferResult
- Raises:
IncompleteTransfer – If the uploaded size is wrong (retried).
- biomero.ssh_recovery.bounded_read_timeout(client: Any, requested: float | None) float | None[source]
Return the timeout for a short read-only command.
- Parameters:
client (Any) – The
SlurmClient, inside ascope.requested (Optional[float]) – A longer timeout the caller asked for because the read is legitimately slow.
- Returns:
- The requested timeout (capped by what is left of an
outage), or the detection limit when none was requested. The request is returned unchanged when recovery is off.
- Return type:
Optional[float]
- biomero.ssh_recovery.download(connection: Connection, remote: str, directory: str) Result
Download a file so that the local name never shows a partial file.
The data goes to a temporary local file, is checked against the remote file (unchanged and complete), and then replaces the local file. An earlier complete local file stays available until then.
- Parameters:
- Returns:
The result, with
localset to the final path.- Return type:
TransferResult
- Raises:
IncompleteTransfer – If the remote file changed or the download is incomplete (retried).
- biomero.ssh_recovery.io_timeout(client: Any, configured: float | None = None) float[source]
Return the native limit for connection stages and short reads.
This is a detection limit, not a limit on healthy long commands. It is never longer than the recovery window, and during an outage never longer than what is left of it.
- biomero.ssh_recovery.is_transient(error: BaseException) bool[source]
Tell whether an error is transport loss (see
transient_reason).- Parameters:
error (BaseException) – The error raised by an SSH operation.
- Returns:
True if retrying may help.
- Return type:
- biomero.ssh_recovery.limit_channel_open(client: Any) None[source]
Limit channel opening on the current transport, within native_timeouts.
Remembers the transport’s own setting so that
native_timeoutscan put it back. Does nothing outsidenative_timeouts.- Parameters:
client (Any) – The
SlurmClient.
- biomero.ssh_recovery.native_timeouts(client: Any) Iterator[None][source]
Bound connection stages with the supported Fabric/Paramiko settings.
Within an attempt the banner, authentication, connect and channel-open timeouts are limited by
io_timeout; the previous values are restored afterwards, also on a reconnected transport. Nothing happens when recovery is off. Paramiko’s exec/subsystem acknowledgement waits and name resolution are not covered by these settings.- Parameters:
client (Any) – The
SlurmClient, inside ascope.- Yields:
None – Control, while the temporary limits are in force.
- biomero.ssh_recovery.read_only(function: Callable[[...], Any]) Callable[[...], Any][source]
Declare a short remote read that is safe to repeat.
The decorated method keeps its signature. It runs through
retrywith a bounded timeout, so that a silent stall returns control; a timeout counts as a lost connection (the Slurm job has not failed).- Parameters:
function (Callable[..., Any]) – A method taking
clientfirst.- Returns:
The wrapped method.
- Return type:
Callable[…, Any]
- biomero.ssh_recovery.retry(client: Any, operation: Callable[[], Any], description: str, *, heartbeat: Callable[[], None] | None = None) Any[source]
Run an operation that is safe to repeat, recovering from SSH loss.
On a lost connection the stale transport is closed and the operation is tried again with growing pauses, until the window set by
client.ssh_recovery_timeoutends. The window starts at the first failure of this call and is not extended by anything else. With a window of 0 the operation runs once and its own error is raised.- Parameters:
client (Any) – The
SlurmClient.operation (Callable[[], Any]) – The repeatable operation.
description (str) – What the operation does, for logs and errors.
heartbeat (Optional[Callable[[], None]]) – A callback that runs during waits.
- Returns:
The result of the first successful attempt.
- Return type:
Any
- Raises:
SSHRecoveryTimeout – If the connection did not come back in time.
RemoteOperationStillPending – If a healthy remote operation was still pending when the window ended.
SSHRecoveryCancelled – If the caller cancelled during a wait.
- biomero.ssh_recovery.scope(client: Any, heartbeat: Callable[[], None] | None = None) Iterator[RecoveryState][source]
Share recovery state and caller callbacks with nested operations.
The outermost scope creates the state from the client’s
ssh_recovery_timeout; nested scopes join it.- Parameters:
client (Any) – The
SlurmClient.heartbeat (Optional[Callable[[], None]]) – A caller callback that runs during waits, such as a session keepalive.
- Yields:
RecoveryState – The shared state.
- Raises:
TypeError – If
heartbeatis not callable.
- biomero.ssh_recovery.sftp_timeout(client: Any) Iterator[Any][source]
Bound each SFTP read, not the whole transfer.
- Parameters:
client (Any) – The
SlurmClient, inside ascope.- Yields:
paramiko.SFTPClient – The SFTP client.
- biomero.ssh_recovery.transient_reason(error: BaseException) str | None[source]
Explain why an error counts as a lost connection, if it does.
Credentials, host keys and remote command failures never count.
- Parameters:
error (BaseException) – The error raised by an SSH operation.
- Returns:
- A short reason when the error is transport loss, else
None.
- Return type:
Optional[str]
biomero.remote_scripts module
Shell scripts that BIOMERO runs durably on the cluster.
After a lost SSH connection a caller cannot know whether its remote command
ran. These builders make a command safe to ask again: it runs under a lock and
leaves a marker or receipt file, so that a second request finds the first
result instead of repeating the work (for example a second sbatch).
The builders only create strings and know nothing about connections; the
caller (SlurmClient) runs them. Each script is built from small named
parts, so you can read what it does without tracing nested quotes.
Receipt protocol of submit_once_script. All files share one prefix, the
state prefix (<slurm_data_path>/.biomero-recovery/<task id>):
.lock: the lock file; one submission per prefix runs at a time..digest: hash of the command, to notice a changed command on resume..intent: written BEFORE sbatch runs. It holds the submission time. An intent without a.jobmeans the outcome of sbatch is unknown..job: the Slurm job id, published atomically once known..failed: sbatch refused the job (no job exists); keeps the output..stdout/.stderr: the output of the sbatch call.
Exit codes with a meaning to the caller: REMOTE_BUSY_EXIT_CODE (the lock
is held elsewhere, or the job is not visible in Slurm yet; ask again later)
and SUBMISSION_REJECTED_EXIT_CODE (sbatch refused the job).
- biomero.remote_scripts.create_then_publish_script(create_command: str, partial_file: str, final_file: str) str[source]
Create a file under a temporary name and rename it when complete.
- biomero.remote_scripts.locked_script(lock_template: str, lock_file: str, script: str, wait_seconds: int = 5) str[source]
Run a script while holding a lock on the cluster.
The lock command (
flockby default) takes an exclusive lock on the lock file and then runs the script, so concurrent callers run one at a time. A caller that waits longer thanwait_secondsgetsREMOTE_BUSY_EXIT_CODEinstead of the script’s own result.
- biomero.remote_scripts.remove_state_files_command(state_prefix: str) str[source]
Build the command that removes the receipt files of one submission.
- biomero.remote_scripts.run_once_script(work_command: str, done_marker: str, *, stale_if_newer: Iterable[str] = (), published_file: str | None = None, reuse_message: str = 'Reusing the completed result') str[source]
Run a command once and skip it when its marker shows it completed.
The marker records a finished run. A finished run is reused only while it is still current: not when an input is newer than the marker (a zip that was uploaded again, results that changed), nor when the published file no longer has the recorded size.
- Parameters:
work_command (str) – The command to run when there is no current marker.
done_marker (str) – Remote path of the marker file.
stale_if_newer (Iterable[str]) – Remote paths; if any of them (or anything below a directory) is newer than the marker, the work runs again.
published_file (Optional[str]) – A file the work produces. Its size is stored in the marker and compared on reuse.
reuse_message (str) – Printed when the marker is reused.
- Returns:
The shell script.
- Return type:
- biomero.remote_scripts.submit_once_script(sbatch_command: str, state_prefix: str, job_name: str, command_digest: str, *, verify_command_unchanged: bool = True, remember_rejection: bool = True) str[source]
Submit a Slurm job exactly once, however often the script is run.
Run again after a lost connection, the script adopts the job recorded by the first run; when the first run died between sbatch and the record, it finds the job by its name in Slurm. It never runs sbatch a second time while an earlier attempt may have created a job.
- Parameters:
sbatch_command (str) – The submission command. Its job name must be
job_name, because that name is how a lost job is found again.state_prefix (str) – Remote path prefix of the receipt files.
job_name (str) – The Slurm job name of this submission.
command_digest (str) – Hash of the command and its environment.
verify_command_unchanged (bool) – Stop when a recorded submission used a different command (default). Without it, no digest is kept.
remember_rejection (bool) – Keep a
.failedreceipt when sbatch refuses the job, and repeat that answer on later calls (default). Without it the attempt is forgotten, so a later call submits again.
- Returns:
The shell script. It prints
Submitted batch job <id>.- Return type: