toil 9.1.1__py3-none-any.whl → 9.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- toil/__init__.py +5 -9
- toil/batchSystems/abstractBatchSystem.py +23 -22
- toil/batchSystems/abstractGridEngineBatchSystem.py +17 -12
- toil/batchSystems/awsBatch.py +8 -8
- toil/batchSystems/cleanup_support.py +4 -4
- toil/batchSystems/contained_executor.py +3 -3
- toil/batchSystems/gridengine.py +3 -4
- toil/batchSystems/htcondor.py +5 -5
- toil/batchSystems/kubernetes.py +65 -63
- toil/batchSystems/local_support.py +2 -3
- toil/batchSystems/lsf.py +6 -7
- toil/batchSystems/mesos/batchSystem.py +11 -7
- toil/batchSystems/mesos/test/__init__.py +1 -2
- toil/batchSystems/options.py +9 -10
- toil/batchSystems/registry.py +3 -7
- toil/batchSystems/singleMachine.py +8 -11
- toil/batchSystems/slurm.py +49 -38
- toil/batchSystems/torque.py +3 -4
- toil/bus.py +36 -34
- toil/common.py +129 -89
- toil/cwl/cwltoil.py +857 -729
- toil/cwl/utils.py +44 -35
- toil/fileStores/__init__.py +3 -1
- toil/fileStores/abstractFileStore.py +28 -30
- toil/fileStores/cachingFileStore.py +8 -8
- toil/fileStores/nonCachingFileStore.py +10 -21
- toil/job.py +159 -158
- toil/jobStores/abstractJobStore.py +68 -69
- toil/jobStores/aws/jobStore.py +249 -213
- toil/jobStores/aws/utils.py +13 -24
- toil/jobStores/fileJobStore.py +28 -22
- toil/jobStores/googleJobStore.py +21 -17
- toil/jobStores/utils.py +3 -7
- toil/leader.py +17 -22
- toil/lib/accelerators.py +6 -4
- toil/lib/aws/__init__.py +9 -10
- toil/lib/aws/ami.py +33 -19
- toil/lib/aws/iam.py +6 -6
- toil/lib/aws/s3.py +259 -157
- toil/lib/aws/session.py +76 -76
- toil/lib/aws/utils.py +51 -43
- toil/lib/checksum.py +19 -15
- toil/lib/compatibility.py +3 -2
- toil/lib/conversions.py +45 -18
- toil/lib/directory.py +29 -26
- toil/lib/docker.py +93 -99
- toil/lib/dockstore.py +77 -50
- toil/lib/ec2.py +39 -38
- toil/lib/ec2nodes.py +11 -4
- toil/lib/exceptions.py +8 -5
- toil/lib/ftp_utils.py +9 -14
- toil/lib/generatedEC2Lists.py +161 -20
- toil/lib/history.py +141 -97
- toil/lib/history_submission.py +163 -72
- toil/lib/io.py +27 -17
- toil/lib/memoize.py +2 -1
- toil/lib/misc.py +15 -11
- toil/lib/pipes.py +40 -25
- toil/lib/plugins.py +12 -8
- toil/lib/resources.py +1 -0
- toil/lib/retry.py +32 -38
- toil/lib/threading.py +12 -12
- toil/lib/throttle.py +1 -2
- toil/lib/trs.py +113 -51
- toil/lib/url.py +14 -23
- toil/lib/web.py +7 -2
- toil/options/common.py +18 -15
- toil/options/cwl.py +2 -2
- toil/options/runner.py +9 -5
- toil/options/wdl.py +1 -3
- toil/provisioners/__init__.py +9 -9
- toil/provisioners/abstractProvisioner.py +22 -20
- toil/provisioners/aws/__init__.py +20 -14
- toil/provisioners/aws/awsProvisioner.py +10 -8
- toil/provisioners/clusterScaler.py +19 -18
- toil/provisioners/gceProvisioner.py +2 -3
- toil/provisioners/node.py +11 -13
- toil/realtimeLogger.py +4 -4
- toil/resource.py +5 -5
- toil/server/app.py +2 -2
- toil/server/cli/wes_cwl_runner.py +11 -11
- toil/server/utils.py +18 -21
- toil/server/wes/abstract_backend.py +9 -8
- toil/server/wes/amazon_wes_utils.py +3 -3
- toil/server/wes/tasks.py +3 -5
- toil/server/wes/toil_backend.py +17 -21
- toil/server/wsgi_app.py +3 -3
- toil/serviceManager.py +3 -4
- toil/statsAndLogging.py +12 -13
- toil/test/__init__.py +33 -24
- toil/test/batchSystems/batchSystemTest.py +12 -11
- toil/test/batchSystems/batch_system_plugin_test.py +3 -5
- toil/test/batchSystems/test_slurm.py +38 -24
- toil/test/cwl/conftest.py +5 -6
- toil/test/cwl/cwlTest.py +194 -78
- toil/test/cwl/download_file_uri.json +6 -0
- toil/test/cwl/download_file_uri_no_hostname.json +6 -0
- toil/test/docs/scripts/tutorial_staging.py +1 -0
- toil/test/jobStores/jobStoreTest.py +9 -7
- toil/test/lib/aws/test_iam.py +1 -3
- toil/test/lib/aws/test_s3.py +1 -1
- toil/test/lib/dockerTest.py +9 -9
- toil/test/lib/test_ec2.py +12 -11
- toil/test/lib/test_history.py +4 -4
- toil/test/lib/test_trs.py +16 -14
- toil/test/lib/test_url.py +7 -6
- toil/test/lib/url_plugin_test.py +12 -18
- toil/test/provisioners/aws/awsProvisionerTest.py +10 -8
- toil/test/provisioners/clusterScalerTest.py +2 -5
- toil/test/provisioners/clusterTest.py +1 -3
- toil/test/server/serverTest.py +13 -4
- toil/test/sort/restart_sort.py +2 -6
- toil/test/sort/sort.py +3 -8
- toil/test/src/deferredFunctionTest.py +7 -7
- toil/test/src/environmentTest.py +1 -2
- toil/test/src/fileStoreTest.py +5 -5
- toil/test/src/importExportFileTest.py +5 -6
- toil/test/src/jobServiceTest.py +22 -14
- toil/test/src/jobTest.py +121 -25
- toil/test/src/miscTests.py +5 -7
- toil/test/src/promisedRequirementTest.py +8 -7
- toil/test/src/regularLogTest.py +2 -3
- toil/test/src/resourceTest.py +5 -8
- toil/test/src/restartDAGTest.py +5 -6
- toil/test/src/resumabilityTest.py +2 -2
- toil/test/src/retainTempDirTest.py +3 -3
- toil/test/src/systemTest.py +3 -3
- toil/test/src/threadingTest.py +1 -1
- toil/test/src/workerTest.py +1 -2
- toil/test/utils/toilDebugTest.py +6 -4
- toil/test/utils/toilKillTest.py +1 -1
- toil/test/utils/utilsTest.py +15 -14
- toil/test/wdl/wdltoil_test.py +247 -124
- toil/test/wdl/wdltoil_test_kubernetes.py +2 -2
- toil/toilState.py +2 -3
- toil/utils/toilDebugFile.py +3 -8
- toil/utils/toilDebugJob.py +1 -2
- toil/utils/toilLaunchCluster.py +1 -2
- toil/utils/toilSshCluster.py +2 -0
- toil/utils/toilStats.py +19 -24
- toil/utils/toilStatus.py +11 -14
- toil/version.py +10 -10
- toil/wdl/wdltoil.py +313 -209
- toil/worker.py +18 -12
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/METADATA +11 -14
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/RECORD +150 -153
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/WHEEL +1 -1
- toil/test/cwl/staging_cat.cwl +0 -27
- toil/test/cwl/staging_make_file.cwl +0 -25
- toil/test/cwl/staging_workflow.cwl +0 -43
- toil/test/cwl/zero_default.cwl +0 -61
- toil/test/utils/ABCWorkflowDebug/ABC.txt +0 -1
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/entry_points.txt +0 -0
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/licenses/LICENSE +0 -0
- {toil-9.1.1.dist-info → toil-9.2.0.dist-info}/top_level.txt +0 -0
toil/batchSystems/slurm.py
CHANGED
|
@@ -17,12 +17,12 @@ import errno
|
|
|
17
17
|
import logging
|
|
18
18
|
import math
|
|
19
19
|
import os
|
|
20
|
-
import sys
|
|
21
20
|
import shlex
|
|
22
|
-
|
|
21
|
+
import sys
|
|
23
22
|
from argparse import SUPPRESS, ArgumentParser, _ArgumentGroup
|
|
24
|
-
from
|
|
25
|
-
from
|
|
23
|
+
from collections.abc import Callable
|
|
24
|
+
from datetime import datetime, timedelta
|
|
25
|
+
from typing import NamedTuple, TypeVar
|
|
26
26
|
|
|
27
27
|
from toil.batchSystems.abstractBatchSystem import (
|
|
28
28
|
EXIT_STATUS_UNAVAILABLE_VALUE,
|
|
@@ -103,6 +103,7 @@ def parse_slurm_time(slurm_time: str) -> int:
|
|
|
103
103
|
total_seconds += multiplier * int(elapsed_split[index])
|
|
104
104
|
return total_seconds
|
|
105
105
|
|
|
106
|
+
|
|
106
107
|
# For parsing user-provided option overrides (or self-generated
|
|
107
108
|
# options) for sbatch, we need a way to recognize long, long-with-equals, and
|
|
108
109
|
# short forms.
|
|
@@ -111,23 +112,34 @@ def option_detector(long: str, short: str | None = None) -> Callable[[str], bool
|
|
|
111
112
|
Get a function that returns true if it sees the long or short
|
|
112
113
|
option.
|
|
113
114
|
"""
|
|
115
|
+
|
|
114
116
|
def is_match(option: str) -> bool:
|
|
115
|
-
return
|
|
117
|
+
return (
|
|
118
|
+
option == f"--{long}"
|
|
119
|
+
or option.startswith(f"--{long}=")
|
|
120
|
+
or (short is not None and option == f"-{short}")
|
|
121
|
+
)
|
|
122
|
+
|
|
116
123
|
return is_match
|
|
117
124
|
|
|
125
|
+
|
|
118
126
|
def any_option_detector(options: list[str | tuple[str, str]]) -> Callable[[str], bool]:
|
|
119
127
|
"""
|
|
120
128
|
Get a function that returns true if it sees any of the long
|
|
121
129
|
options or long or short option pairs.
|
|
122
130
|
"""
|
|
123
|
-
detectors = [
|
|
131
|
+
detectors = [
|
|
132
|
+
option_detector(o) if isinstance(o, str) else option_detector(*o)
|
|
133
|
+
for o in options
|
|
134
|
+
]
|
|
135
|
+
|
|
124
136
|
def is_match(option: str) -> bool:
|
|
125
137
|
for detector in detectors:
|
|
126
138
|
if detector(option):
|
|
127
139
|
return True
|
|
128
140
|
return False
|
|
129
|
-
return is_match
|
|
130
141
|
|
|
142
|
+
return is_match
|
|
131
143
|
|
|
132
144
|
|
|
133
145
|
class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
@@ -352,17 +364,17 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
352
364
|
) -> list[int | tuple[int, BatchJobExitReason | None] | None]:
|
|
353
365
|
"""
|
|
354
366
|
Collect all job exit codes in a single call.
|
|
355
|
-
|
|
367
|
+
|
|
356
368
|
:param batch_job_id_list: list of Job ID strings, where each string
|
|
357
369
|
has the form ``<job>[.<task>]``.
|
|
358
|
-
|
|
370
|
+
|
|
359
371
|
:return: list of job exit codes or exit code, exit reason pairs
|
|
360
372
|
associated with the list of job IDs.
|
|
361
|
-
|
|
373
|
+
|
|
362
374
|
:raises CalledProcessErrorStderr: if communicating with Slurm went
|
|
363
375
|
wrong.
|
|
364
|
-
|
|
365
|
-
:raises OSError: if job details are not available
|
|
376
|
+
|
|
377
|
+
:raises OSError: if job details are not available because a Slurm
|
|
366
378
|
command could not start.
|
|
367
379
|
"""
|
|
368
380
|
logger.log(
|
|
@@ -402,12 +414,12 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
402
414
|
value is a tuple containing the job's state and exit code.
|
|
403
415
|
:raises CalledProcessErrorStderr: if communicating with Slurm went
|
|
404
416
|
wrong.
|
|
405
|
-
:raises OSError: if job details are not available
|
|
417
|
+
:raises OSError: if job details are not available because a Slurm
|
|
406
418
|
command could not start.
|
|
407
419
|
"""
|
|
408
420
|
|
|
409
421
|
status_dict = {}
|
|
410
|
-
scontrol_problem:
|
|
422
|
+
scontrol_problem: Exception | None = None
|
|
411
423
|
|
|
412
424
|
try:
|
|
413
425
|
# Get all the job details we can from scontrol, which we think
|
|
@@ -445,7 +457,6 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
445
457
|
# values filled in for all jobs.
|
|
446
458
|
assert len(status_dict) == len(job_id_list)
|
|
447
459
|
|
|
448
|
-
|
|
449
460
|
return status_dict
|
|
450
461
|
|
|
451
462
|
def _get_job_return_code(
|
|
@@ -516,7 +527,11 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
516
527
|
|
|
517
528
|
return state_token
|
|
518
529
|
|
|
519
|
-
def _remaining_jobs(
|
|
530
|
+
def _remaining_jobs(
|
|
531
|
+
self,
|
|
532
|
+
job_id_list: list[int],
|
|
533
|
+
job_details: dict[int, tuple[str | None, int | None]],
|
|
534
|
+
) -> list[int]:
|
|
520
535
|
"""
|
|
521
536
|
Given a list of job IDs and a list of job details (state and exit
|
|
522
537
|
code), get the list of job IDs where the details are (None, None)
|
|
@@ -550,13 +565,7 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
550
565
|
# Pick a now
|
|
551
566
|
now = datetime.now().astimezone(None)
|
|
552
567
|
# Decide when to start the search (first copy of past midnight)
|
|
553
|
-
begin_time = now.replace(
|
|
554
|
-
hour=0,
|
|
555
|
-
minute=0,
|
|
556
|
-
second=0,
|
|
557
|
-
microsecond=0,
|
|
558
|
-
fold=0
|
|
559
|
-
)
|
|
568
|
+
begin_time = now.replace(hour=0, minute=0, second=0, microsecond=0, fold=0)
|
|
560
569
|
# And when to end (a day after that)
|
|
561
570
|
end_time = begin_time + timedelta(days=1)
|
|
562
571
|
while end_time < now:
|
|
@@ -575,9 +584,7 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
575
584
|
# started.
|
|
576
585
|
results.update(
|
|
577
586
|
self._get_job_details_from_sacct_for_range(
|
|
578
|
-
job_id_list,
|
|
579
|
-
begin_time,
|
|
580
|
-
end_time
|
|
587
|
+
job_id_list, begin_time, end_time
|
|
581
588
|
)
|
|
582
589
|
)
|
|
583
590
|
job_id_list = self._remaining_jobs(job_id_list, results)
|
|
@@ -588,14 +595,13 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
588
595
|
end_time = begin_time + timedelta(seconds=1)
|
|
589
596
|
begin_time = end_time - timedelta(days=1, seconds=1)
|
|
590
597
|
|
|
591
|
-
|
|
592
598
|
if end_time < self.boss.start_time and len(job_id_list) > 0:
|
|
593
599
|
# This is suspicious.
|
|
594
600
|
logger.warning(
|
|
595
601
|
"Could not find any information from sacct after "
|
|
596
602
|
"workflow start at %s about jobs: %s",
|
|
597
603
|
self.boss.start_time.isoformat(),
|
|
598
|
-
job_id_list
|
|
604
|
+
job_id_list,
|
|
599
605
|
)
|
|
600
606
|
|
|
601
607
|
return results
|
|
@@ -622,6 +628,7 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
622
628
|
|
|
623
629
|
assert begin_time.tzinfo is not None, "begin_time must be aware"
|
|
624
630
|
assert end_time.tzinfo is not None, "end_time must be aware"
|
|
631
|
+
|
|
625
632
|
def stringify(t: datetime) -> str:
|
|
626
633
|
"""
|
|
627
634
|
Convert an aware time local time, and format it *without* a
|
|
@@ -662,14 +669,14 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
662
669
|
raise
|
|
663
670
|
job_statuses.update(
|
|
664
671
|
self._get_job_details_from_sacct_for_range(
|
|
665
|
-
job_id_list[:len(job_id_list)//2],
|
|
672
|
+
job_id_list[: len(job_id_list) // 2],
|
|
666
673
|
begin_time,
|
|
667
674
|
end_time,
|
|
668
675
|
)
|
|
669
676
|
)
|
|
670
677
|
job_statuses.update(
|
|
671
678
|
self._get_job_details_from_sacct_for_range(
|
|
672
|
-
job_id_list[len(job_id_list)//2:],
|
|
679
|
+
job_id_list[len(job_id_list) // 2 :],
|
|
673
680
|
begin_time,
|
|
674
681
|
end_time,
|
|
675
682
|
)
|
|
@@ -845,8 +852,12 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
845
852
|
# Also any extra arguments from --slurmArgs or TOIL_SLURM_ARGS
|
|
846
853
|
nativeConfig: str = self.boss.config.slurm_args # type: ignore[attr-defined]
|
|
847
854
|
|
|
848
|
-
is_any_mem_option = any_option_detector(
|
|
849
|
-
|
|
855
|
+
is_any_mem_option = any_option_detector(
|
|
856
|
+
["mem", "mem-per-cpu", "mem-per-gpu"]
|
|
857
|
+
)
|
|
858
|
+
is_any_cpus_option = any_option_detector(
|
|
859
|
+
[("cpus-per-task", "c"), "cpus-per-gpu"]
|
|
860
|
+
)
|
|
850
861
|
is_export_option = option_detector("export")
|
|
851
862
|
is_export_file_option = option_detector("export-file")
|
|
852
863
|
is_time_option = option_detector("time", "t")
|
|
@@ -857,7 +868,7 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
857
868
|
|
|
858
869
|
# --export=[ALL,]<environment_toil_variables>
|
|
859
870
|
export_all = True
|
|
860
|
-
export_list = []
|
|
871
|
+
export_list = [] # Some items here may be multiple comma-separated values
|
|
861
872
|
time_limit: int | None = self.boss.config.slurm_time # type: ignore[attr-defined]
|
|
862
873
|
partition: str | None = None
|
|
863
874
|
|
|
@@ -967,10 +978,7 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
967
978
|
raise RuntimeError(
|
|
968
979
|
f"The job {jobName} is requesting GPUs, but the Slurm cluster does not appear to have an accessible partition with GPUs"
|
|
969
980
|
)
|
|
970
|
-
if
|
|
971
|
-
time_limit is not None
|
|
972
|
-
and gpu_partition.time_limit < time_limit
|
|
973
|
-
):
|
|
981
|
+
if time_limit is not None and gpu_partition.time_limit < time_limit:
|
|
974
982
|
# TODO: find the lowest-priority GPU partition that has at least each job's time limit!
|
|
975
983
|
logger.warning(
|
|
976
984
|
"Trying to submit a job that needs %s seconds to partition %s that has a limit of %s seconds",
|
|
@@ -993,7 +1001,10 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
993
1001
|
if gpus:
|
|
994
1002
|
# Generate GPU assignment argument
|
|
995
1003
|
sbatch_line.append(f"--gres=gpu:{gpus}")
|
|
996
|
-
if
|
|
1004
|
+
if (
|
|
1005
|
+
partition is not None
|
|
1006
|
+
and partition not in self.boss.partitions.gpu_partitions
|
|
1007
|
+
):
|
|
997
1008
|
# the specified partition is not compatible, so warn the user that the job may not work
|
|
998
1009
|
logger.warning(
|
|
999
1010
|
f"Job {jobName} needs GPUs, but specified partition {partition} does not have them. This job may not work."
|
toil/batchSystems/torque.py
CHANGED
|
@@ -18,7 +18,6 @@ import shlex
|
|
|
18
18
|
import tempfile
|
|
19
19
|
from queue import Empty
|
|
20
20
|
from shlex import quote
|
|
21
|
-
from typing import Optional
|
|
22
21
|
|
|
23
22
|
from toil.batchSystems.abstractGridEngineBatchSystem import (
|
|
24
23
|
AbstractGridEngineBatchSystem,
|
|
@@ -137,8 +136,8 @@ class TorqueBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
137
136
|
jobID: int,
|
|
138
137
|
command: str,
|
|
139
138
|
jobName: str,
|
|
140
|
-
job_environment:
|
|
141
|
-
gpus:
|
|
139
|
+
job_environment: dict[str, str] | None = None,
|
|
140
|
+
gpus: int | None = None,
|
|
142
141
|
) -> list[str]:
|
|
143
142
|
return self.prepareQsub(cpu, memory, jobID, job_environment) + [
|
|
144
143
|
self.generateTorqueWrapper(command, jobID)
|
|
@@ -186,7 +185,7 @@ class TorqueBatchSystem(AbstractGridEngineBatchSystem):
|
|
|
186
185
|
cpu: int,
|
|
187
186
|
mem: int,
|
|
188
187
|
jobID: int,
|
|
189
|
-
job_environment:
|
|
188
|
+
job_environment: dict[str, str] | None,
|
|
190
189
|
) -> list[str]:
|
|
191
190
|
|
|
192
191
|
# TODO: passing $PWD on command line not working for -d, resorting to
|
toil/bus.py
CHANGED
|
@@ -67,9 +67,9 @@ import os
|
|
|
67
67
|
import queue
|
|
68
68
|
import tempfile
|
|
69
69
|
import threading
|
|
70
|
-
from collections.abc import Iterator
|
|
70
|
+
from collections.abc import Callable, Iterator
|
|
71
71
|
from dataclasses import dataclass
|
|
72
|
-
from typing import IO, Any,
|
|
72
|
+
from typing import IO, Any, NamedTuple, Optional, TypeVar, cast
|
|
73
73
|
|
|
74
74
|
from pubsub.core import Publisher
|
|
75
75
|
from pubsub.core.listener import Listener
|
|
@@ -282,7 +282,7 @@ def bytes_to_message(message_type: type[MessageType], data: bytes) -> MessageTyp
|
|
|
282
282
|
# Get a mapping from field name to type in the named tuple.
|
|
283
283
|
# We need to check a couple different fields because this moved in a recent
|
|
284
284
|
# Python 3 release.
|
|
285
|
-
field_to_type:
|
|
285
|
+
field_to_type: dict[str, type] | None = cast(
|
|
286
286
|
Optional[dict[str, type]],
|
|
287
287
|
getattr(
|
|
288
288
|
message_type, "__annotations__", getattr(message_type, "_field_types", None)
|
|
@@ -369,7 +369,7 @@ class MessageBus:
|
|
|
369
369
|
# We are supposed to receive messages
|
|
370
370
|
while True:
|
|
371
371
|
# Until we can't get a message, get one
|
|
372
|
-
message:
|
|
372
|
+
message: Any | None = None
|
|
373
373
|
try:
|
|
374
374
|
message = self._queue.get_nowait()
|
|
375
375
|
except queue.Empty:
|
|
@@ -528,7 +528,7 @@ class MessageBusClient:
|
|
|
528
528
|
"""
|
|
529
529
|
|
|
530
530
|
# We might be given a reference to the message bus
|
|
531
|
-
self._bus:
|
|
531
|
+
self._bus: MessageBus | None = None
|
|
532
532
|
|
|
533
533
|
def _set_bus(self, bus: MessageBus) -> None:
|
|
534
534
|
"""
|
|
@@ -775,43 +775,45 @@ def replay_message_bus(path: FileDescriptorOrPath) -> dict[str, JobStatus]:
|
|
|
775
775
|
# And for each of them
|
|
776
776
|
logger.debug("Got message from workflow: %s", event)
|
|
777
777
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
event.
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
778
|
+
match event:
|
|
779
|
+
case JobUpdatedMessage():
|
|
780
|
+
# Apply the latest return code from the job with this ID.
|
|
781
|
+
job_statuses[event.job_id].exit_code = event.result_status
|
|
782
|
+
case JobIssuedMessage():
|
|
783
|
+
job_statuses[event.job_id].job_store_id = event.job_id
|
|
784
|
+
job_statuses[event.job_id].name = event.job_type
|
|
785
|
+
job_statuses[event.job_id].toil_batch_id = event.toil_batch_id
|
|
786
|
+
job_statuses[event.job_id].exit_code = -1
|
|
787
|
+
batch_to_job_id[event.toil_batch_id] = event.job_id
|
|
788
|
+
case JobCompletedMessage():
|
|
789
|
+
job_statuses[event.job_id].name = event.job_type
|
|
790
|
+
job_statuses[event.job_id].exit_code = event.exit_code
|
|
791
|
+
case JobFailedMessage():
|
|
792
|
+
job_statuses[event.job_id].name = event.job_type
|
|
793
|
+
if job_statuses[event.job_id].exit_code == 0:
|
|
794
|
+
# Record the failure if we never got a failed exit code.
|
|
795
|
+
job_statuses[event.job_id].exit_code = 1
|
|
796
|
+
case JobAnnotationMessage():
|
|
797
|
+
# Remember the last value of any annotation that is set
|
|
798
|
+
job_statuses[event.job_id].annotations[
|
|
799
|
+
event.annotation_name
|
|
800
|
+
] = event.annotation_value
|
|
801
|
+
case ExternalBatchIdMessage() as ebim if (
|
|
802
|
+
ebim.toil_batch_id in batch_to_job_id
|
|
803
|
+
):
|
|
802
804
|
job_statuses[
|
|
803
|
-
batch_to_job_id[
|
|
804
|
-
].external_batch_id =
|
|
805
|
+
batch_to_job_id[ebim.toil_batch_id]
|
|
806
|
+
].external_batch_id = ebim.external_batch_id
|
|
805
807
|
job_statuses[
|
|
806
|
-
batch_to_job_id[
|
|
807
|
-
].batch_system =
|
|
808
|
+
batch_to_job_id[ebim.toil_batch_id]
|
|
809
|
+
].batch_system = ebim.batch_system
|
|
808
810
|
except FileNotFoundError:
|
|
809
811
|
logger.warning("We were unable to access the file")
|
|
810
812
|
|
|
811
813
|
return job_statuses
|
|
812
814
|
|
|
813
815
|
|
|
814
|
-
def gen_message_bus_path(tmpdir:
|
|
816
|
+
def gen_message_bus_path(tmpdir: str | None = None) -> str:
|
|
815
817
|
"""
|
|
816
818
|
Return a file path in tmp to store the message bus at.
|
|
817
819
|
Calling function is responsible for cleaning the generated file.
|