toil 9.1.2__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 +14 -14
- 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.2.dist-info → toil-9.2.0.dist-info}/METADATA +11 -14
- {toil-9.1.2.dist-info → toil-9.2.0.dist-info}/RECORD +150 -153
- {toil-9.1.2.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.2.dist-info → toil-9.2.0.dist-info}/entry_points.txt +0 -0
- {toil-9.1.2.dist-info → toil-9.2.0.dist-info}/licenses/LICENSE +0 -0
- {toil-9.1.2.dist-info → toil-9.2.0.dist-info}/top_level.txt +0 -0
toil/lib/history.py
CHANGED
|
@@ -16,16 +16,16 @@
|
|
|
16
16
|
Contains tools for tracking history.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
from contextlib import contextmanager
|
|
20
19
|
import logging
|
|
21
20
|
import os
|
|
22
21
|
import sqlite3
|
|
23
22
|
import sys
|
|
24
|
-
import threading
|
|
25
23
|
import time
|
|
26
24
|
import uuid
|
|
25
|
+
from collections.abc import Callable, Iterable, Iterator
|
|
26
|
+
from contextlib import contextmanager
|
|
27
27
|
from dataclasses import dataclass
|
|
28
|
-
from typing import
|
|
28
|
+
from typing import TypeVar
|
|
29
29
|
|
|
30
30
|
from toil.lib.conversions import strtobool
|
|
31
31
|
from toil.lib.io import get_toil_home
|
|
@@ -33,12 +33,13 @@ from toil.lib.retry import ErrorCondition, retry
|
|
|
33
33
|
|
|
34
34
|
logger = logging.getLogger(__name__)
|
|
35
35
|
|
|
36
|
+
|
|
36
37
|
class HistoryDatabaseSchemaTooNewError(RuntimeError):
|
|
37
38
|
"""
|
|
38
39
|
Raised when we would write to the history database, but its schema is too
|
|
39
40
|
new for us to understand.
|
|
40
41
|
"""
|
|
41
|
-
|
|
42
|
+
|
|
42
43
|
|
|
43
44
|
@dataclass
|
|
44
45
|
class WorkflowSummary:
|
|
@@ -47,25 +48,27 @@ class WorkflowSummary:
|
|
|
47
48
|
|
|
48
49
|
Represents all the attempts to execute one run of a workflow.
|
|
49
50
|
"""
|
|
51
|
+
|
|
50
52
|
id: str
|
|
51
|
-
name:
|
|
53
|
+
name: str | None
|
|
52
54
|
job_store: str
|
|
53
55
|
total_attempts: int
|
|
54
56
|
total_job_attempts: int
|
|
55
57
|
succeeded: bool
|
|
56
|
-
start_time:
|
|
58
|
+
start_time: float | None
|
|
57
59
|
"""
|
|
58
60
|
Time when the first workflow attempt started, in seconds since epoch.
|
|
59
61
|
|
|
60
62
|
None if there are no attempts recorded.
|
|
61
63
|
"""
|
|
62
|
-
runtime:
|
|
64
|
+
runtime: float | None
|
|
63
65
|
"""
|
|
64
66
|
Time from the first workflow attempt's start to the last one's end, in seconds.
|
|
65
67
|
|
|
66
68
|
None if there are no attempts recorded.
|
|
67
69
|
"""
|
|
68
|
-
trs_spec:
|
|
70
|
+
trs_spec: str | None
|
|
71
|
+
|
|
69
72
|
|
|
70
73
|
@dataclass
|
|
71
74
|
class WorkflowAttemptSummary:
|
|
@@ -74,20 +77,22 @@ class WorkflowAttemptSummary:
|
|
|
74
77
|
|
|
75
78
|
Helpfully includes the workflow metadata for Dockstore.
|
|
76
79
|
"""
|
|
80
|
+
|
|
77
81
|
workflow_id: str
|
|
78
82
|
attempt_number: int
|
|
79
83
|
succeeded: bool
|
|
80
84
|
start_time: float
|
|
81
85
|
runtime: float
|
|
82
86
|
submitted_to_dockstore: bool
|
|
83
|
-
batch_system:
|
|
84
|
-
caching:
|
|
85
|
-
toil_version:
|
|
86
|
-
python_version:
|
|
87
|
-
platform_system:
|
|
88
|
-
platform_machine:
|
|
87
|
+
batch_system: str | None
|
|
88
|
+
caching: bool | None
|
|
89
|
+
toil_version: str | None
|
|
90
|
+
python_version: str | None
|
|
91
|
+
platform_system: str | None
|
|
92
|
+
platform_machine: str | None
|
|
89
93
|
workflow_job_store: str
|
|
90
|
-
workflow_trs_spec:
|
|
94
|
+
workflow_trs_spec: str | None
|
|
95
|
+
|
|
91
96
|
|
|
92
97
|
@dataclass
|
|
93
98
|
class JobAttemptSummary:
|
|
@@ -95,20 +100,22 @@ class JobAttemptSummary:
|
|
|
95
100
|
Data class holding summary information for a job attempt within a known
|
|
96
101
|
workflow attempt.
|
|
97
102
|
"""
|
|
103
|
+
|
|
98
104
|
id: str
|
|
99
105
|
job_name: str
|
|
100
106
|
succeeded: bool
|
|
101
107
|
start_time: float
|
|
102
108
|
runtime: float
|
|
103
109
|
submitted_to_dockstore: bool
|
|
104
|
-
cores:
|
|
105
|
-
cpu_seconds:
|
|
106
|
-
memory_bytes:
|
|
107
|
-
disk_bytes:
|
|
110
|
+
cores: float | None
|
|
111
|
+
cpu_seconds: float | None
|
|
112
|
+
memory_bytes: int | None
|
|
113
|
+
disk_bytes: int | None
|
|
108
114
|
|
|
109
115
|
|
|
110
116
|
RT = TypeVar("RT")
|
|
111
117
|
|
|
118
|
+
|
|
112
119
|
def db_retry(function: Callable[..., RT]) -> Callable[..., RT]:
|
|
113
120
|
"""
|
|
114
121
|
Decorate a function with the appropriate retries for accessing the database.
|
|
@@ -122,6 +129,7 @@ def db_retry(function: Callable[..., RT]) -> Callable[..., RT]:
|
|
|
122
129
|
],
|
|
123
130
|
)(function)
|
|
124
131
|
|
|
132
|
+
|
|
125
133
|
class HistoryManager:
|
|
126
134
|
"""
|
|
127
135
|
Class responsible for managing the history of Toil runs.
|
|
@@ -134,7 +142,7 @@ class HistoryManager:
|
|
|
134
142
|
|
|
135
143
|
If False, no access at all shoulf be made to the database.
|
|
136
144
|
"""
|
|
137
|
-
return strtobool(os.environ.get("TOIL_HISTORY",
|
|
145
|
+
return strtobool(os.environ.get("TOIL_HISTORY", "True"))
|
|
138
146
|
|
|
139
147
|
@classmethod
|
|
140
148
|
def enabled_job(cls) -> bool:
|
|
@@ -146,10 +154,10 @@ class HistoryManager:
|
|
|
146
154
|
# TODO: When Dockstore can take job metrics alongside whole-workflow
|
|
147
155
|
# metrics, and we've tested to make sure history recording doesn't slow
|
|
148
156
|
# down our leader job processing rate, turn on actual job history logging.
|
|
149
|
-
return cls.enabled() and strtobool(os.environ.get("TOIL_JOB_HISTORY",
|
|
157
|
+
return cls.enabled() and strtobool(os.environ.get("TOIL_JOB_HISTORY", "False"))
|
|
150
158
|
|
|
151
159
|
# For testing, we can move the database path for the class.
|
|
152
|
-
database_path_override:
|
|
160
|
+
database_path_override: str | None = None
|
|
153
161
|
|
|
154
162
|
@classmethod
|
|
155
163
|
def database_path(cls) -> str:
|
|
@@ -180,7 +188,9 @@ class HistoryManager:
|
|
|
180
188
|
if not cls.enabled():
|
|
181
189
|
# Make sure we're not missing an enabled check along any codepath
|
|
182
190
|
# that wants to access the database.
|
|
183
|
-
raise RuntimeError(
|
|
191
|
+
raise RuntimeError(
|
|
192
|
+
"Attempting to connect to database when HistoryManager is disabled!"
|
|
193
|
+
)
|
|
184
194
|
|
|
185
195
|
if not os.path.exists(cls.database_path()):
|
|
186
196
|
# Make the database and protect it from snoopers and busybodies
|
|
@@ -188,10 +198,7 @@ class HistoryManager:
|
|
|
188
198
|
del con
|
|
189
199
|
os.chmod(cls.database_path(), 0o600)
|
|
190
200
|
|
|
191
|
-
con = sqlite3.connect(
|
|
192
|
-
cls.database_path(),
|
|
193
|
-
isolation_level="DEFERRED"
|
|
194
|
-
)
|
|
201
|
+
con = sqlite3.connect(cls.database_path(), isolation_level="DEFERRED")
|
|
195
202
|
|
|
196
203
|
with cls.no_transaction(con):
|
|
197
204
|
# Turn on foreign keys.
|
|
@@ -203,7 +210,7 @@ class HistoryManager:
|
|
|
203
210
|
|
|
204
211
|
# Set up the connection to use the Row class so that we can look up row values by column name and not just order.
|
|
205
212
|
con.row_factory = sqlite3.Row
|
|
206
|
-
|
|
213
|
+
|
|
207
214
|
return con
|
|
208
215
|
|
|
209
216
|
@classmethod
|
|
@@ -215,12 +222,12 @@ class HistoryManager:
|
|
|
215
222
|
|
|
216
223
|
Commits the current transaction.
|
|
217
224
|
"""
|
|
218
|
-
|
|
225
|
+
|
|
219
226
|
con.commit()
|
|
220
|
-
if hasattr(con,
|
|
227
|
+
if hasattr(con, "autocommit"):
|
|
221
228
|
con.autocommit = True
|
|
222
229
|
yield
|
|
223
|
-
if hasattr(con,
|
|
230
|
+
if hasattr(con, "autocommit"):
|
|
224
231
|
con.autocommit = False
|
|
225
232
|
|
|
226
233
|
@classmethod
|
|
@@ -239,12 +246,14 @@ class HistoryManager:
|
|
|
239
246
|
|
|
240
247
|
# TODO: Do a try-and-fall-back to avoid sending the table schema for
|
|
241
248
|
# this every time we do anything.
|
|
242
|
-
cur.execute(
|
|
249
|
+
cur.execute(
|
|
250
|
+
"""
|
|
243
251
|
CREATE TABLE IF NOT EXISTS migrations (
|
|
244
252
|
version INT NOT NULL PRIMARY KEY,
|
|
245
253
|
description TEXT
|
|
246
254
|
)
|
|
247
|
-
"""
|
|
255
|
+
"""
|
|
256
|
+
)
|
|
248
257
|
db_version = next(cur.execute("SELECT MAX(version) FROM migrations"))[0]
|
|
249
258
|
if db_version is None:
|
|
250
259
|
db_version = -1
|
|
@@ -317,25 +326,37 @@ class HistoryManager:
|
|
|
317
326
|
PRIMARY KEY(workflow_id,attempt_number),
|
|
318
327
|
FOREIGN KEY(workflow_id) REFERENCES workflows(id)
|
|
319
328
|
)
|
|
320
|
-
"""
|
|
329
|
+
""",
|
|
321
330
|
],
|
|
322
331
|
),
|
|
323
332
|
]
|
|
324
333
|
|
|
325
334
|
if db_version + 1 > len(migrations):
|
|
326
|
-
raise HistoryDatabaseSchemaTooNewError(
|
|
335
|
+
raise HistoryDatabaseSchemaTooNewError(
|
|
336
|
+
f"History database version is {db_version}, but known migrations only go up to {len(migrations) - 1}"
|
|
337
|
+
)
|
|
327
338
|
|
|
328
339
|
for migration_number in range(db_version + 1, len(migrations)):
|
|
329
|
-
for statement_number, statement in enumerate(
|
|
340
|
+
for statement_number, statement in enumerate(
|
|
341
|
+
migrations[migration_number][1]
|
|
342
|
+
):
|
|
330
343
|
# Run all the migration commands.
|
|
331
344
|
# We don't use executescript() because (on old Pythons?) it
|
|
332
345
|
# commits the current transactrion first.
|
|
333
346
|
try:
|
|
334
347
|
cur.execute(statement)
|
|
335
348
|
except sqlite3.OperationalError:
|
|
336
|
-
logger.exception(
|
|
349
|
+
logger.exception(
|
|
350
|
+
"Could not execute migration %s statement %s: %s",
|
|
351
|
+
migration_number,
|
|
352
|
+
statement_number,
|
|
353
|
+
statement,
|
|
354
|
+
)
|
|
337
355
|
raise
|
|
338
|
-
cur.execute(
|
|
356
|
+
cur.execute(
|
|
357
|
+
"INSERT INTO migrations VALUES (?, ?)",
|
|
358
|
+
(migration_number, migrations[migration_number][0]),
|
|
359
|
+
)
|
|
339
360
|
|
|
340
361
|
# If we did have to migrate, leave everything else we do as part of the migration transaction.
|
|
341
362
|
|
|
@@ -366,13 +387,18 @@ class HistoryManager:
|
|
|
366
387
|
if not cls.enabled():
|
|
367
388
|
return
|
|
368
389
|
|
|
369
|
-
logger.info(
|
|
390
|
+
logger.info(
|
|
391
|
+
"Recording workflow creation of %s in %s", workflow_id, job_store_spec
|
|
392
|
+
)
|
|
370
393
|
|
|
371
394
|
con = cls.connection()
|
|
372
395
|
cur = con.cursor()
|
|
373
396
|
try:
|
|
374
397
|
cls.ensure_tables(con, cur)
|
|
375
|
-
cur.execute(
|
|
398
|
+
cur.execute(
|
|
399
|
+
"INSERT INTO workflows VALUES (?, ?, ?, NULL, NULL)",
|
|
400
|
+
(workflow_id, job_store_spec, time.time()),
|
|
401
|
+
)
|
|
376
402
|
except:
|
|
377
403
|
con.rollback()
|
|
378
404
|
con.close()
|
|
@@ -383,10 +409,11 @@ class HistoryManager:
|
|
|
383
409
|
|
|
384
410
|
# If we raise out of here the connection goes away and the transaction rolls back.
|
|
385
411
|
|
|
386
|
-
|
|
387
412
|
@classmethod
|
|
388
413
|
@db_retry
|
|
389
|
-
def record_workflow_metadata(
|
|
414
|
+
def record_workflow_metadata(
|
|
415
|
+
cls, workflow_id: str, workflow_name: str, trs_spec: str | None = None
|
|
416
|
+
) -> None:
|
|
390
417
|
"""
|
|
391
418
|
Associate a name and optionally a TRS ID and version with a workflow run.
|
|
392
419
|
"""
|
|
@@ -404,9 +431,15 @@ class HistoryManager:
|
|
|
404
431
|
cur = con.cursor()
|
|
405
432
|
try:
|
|
406
433
|
cls.ensure_tables(con, cur)
|
|
407
|
-
cur.execute(
|
|
434
|
+
cur.execute(
|
|
435
|
+
"UPDATE workflows SET name = ? WHERE id = ?",
|
|
436
|
+
(workflow_name, workflow_id),
|
|
437
|
+
)
|
|
408
438
|
if trs_spec is not None:
|
|
409
|
-
cur.execute(
|
|
439
|
+
cur.execute(
|
|
440
|
+
"UPDATE workflows SET trs_spec = ? WHERE id = ?",
|
|
441
|
+
(trs_spec, workflow_id),
|
|
442
|
+
)
|
|
410
443
|
except:
|
|
411
444
|
con.rollback()
|
|
412
445
|
con.close()
|
|
@@ -418,18 +451,18 @@ class HistoryManager:
|
|
|
418
451
|
@classmethod
|
|
419
452
|
@db_retry
|
|
420
453
|
def record_job_attempt(
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
454
|
+
cls,
|
|
455
|
+
workflow_id: str,
|
|
456
|
+
workflow_attempt_number: int,
|
|
457
|
+
job_name: str,
|
|
458
|
+
succeeded: bool,
|
|
459
|
+
start_time: float,
|
|
460
|
+
runtime: float,
|
|
461
|
+
cores: float | None = None,
|
|
462
|
+
cpu_seconds: float | None = None,
|
|
463
|
+
memory_bytes: int | None = None,
|
|
464
|
+
disk_bytes: int | None = None,
|
|
465
|
+
) -> None:
|
|
433
466
|
"""
|
|
434
467
|
Record that a job ran in a workflow.
|
|
435
468
|
|
|
@@ -487,7 +520,7 @@ class HistoryManager:
|
|
|
487
520
|
cpu_seconds,
|
|
488
521
|
memory_bytes,
|
|
489
522
|
disk_bytes,
|
|
490
|
-
)
|
|
523
|
+
),
|
|
491
524
|
)
|
|
492
525
|
except:
|
|
493
526
|
con.rollback()
|
|
@@ -506,12 +539,12 @@ class HistoryManager:
|
|
|
506
539
|
succeeded: bool,
|
|
507
540
|
start_time: float,
|
|
508
541
|
runtime: float,
|
|
509
|
-
batch_system:
|
|
510
|
-
caching:
|
|
511
|
-
toil_version:
|
|
512
|
-
python_version:
|
|
513
|
-
platform_system:
|
|
514
|
-
platform_machine:
|
|
542
|
+
batch_system: str | None = None,
|
|
543
|
+
caching: bool | None = None,
|
|
544
|
+
toil_version: str | None = None,
|
|
545
|
+
python_version: str | None = None,
|
|
546
|
+
platform_system: str | None = None,
|
|
547
|
+
platform_machine: str | None = None,
|
|
515
548
|
) -> None:
|
|
516
549
|
"""
|
|
517
550
|
Record a workflow attempt (start or restart) having finished or failed.
|
|
@@ -561,8 +594,8 @@ class HistoryManager:
|
|
|
561
594
|
toil_version,
|
|
562
595
|
python_version,
|
|
563
596
|
platform_system,
|
|
564
|
-
platform_machine
|
|
565
|
-
)
|
|
597
|
+
platform_machine,
|
|
598
|
+
),
|
|
566
599
|
)
|
|
567
600
|
except:
|
|
568
601
|
con.rollback()
|
|
@@ -572,7 +605,6 @@ class HistoryManager:
|
|
|
572
605
|
con.commit()
|
|
573
606
|
con.close()
|
|
574
607
|
|
|
575
|
-
|
|
576
608
|
##
|
|
577
609
|
# Read methods
|
|
578
610
|
##
|
|
@@ -630,8 +662,13 @@ class HistoryManager:
|
|
|
630
662
|
total_job_attempts=row["total_job_attempts"],
|
|
631
663
|
succeeded=(row["succeeded"] == 1),
|
|
632
664
|
start_time=row["start_time"],
|
|
633
|
-
runtime=(
|
|
634
|
-
|
|
665
|
+
runtime=(
|
|
666
|
+
(row["end_time"] - row["start_time"])
|
|
667
|
+
if row["start_time"] is not None
|
|
668
|
+
and row["end_time"] is not None
|
|
669
|
+
else None
|
|
670
|
+
),
|
|
671
|
+
trs_spec=row["trs_spec"],
|
|
635
672
|
)
|
|
636
673
|
)
|
|
637
674
|
except:
|
|
@@ -646,7 +683,9 @@ class HistoryManager:
|
|
|
646
683
|
|
|
647
684
|
@classmethod
|
|
648
685
|
@db_retry
|
|
649
|
-
def get_submittable_workflow_attempts(
|
|
686
|
+
def get_submittable_workflow_attempts(
|
|
687
|
+
cls, limit: int = sys.maxsize
|
|
688
|
+
) -> list[WorkflowAttemptSummary]:
|
|
650
689
|
"""
|
|
651
690
|
List all workflow attempts not yet submitted to Dockstore.
|
|
652
691
|
|
|
@@ -686,7 +725,7 @@ class HistoryManager:
|
|
|
686
725
|
ORDER BY start_time DESC
|
|
687
726
|
LIMIT ?
|
|
688
727
|
""",
|
|
689
|
-
(limit,)
|
|
728
|
+
(limit,),
|
|
690
729
|
)
|
|
691
730
|
for row in cur:
|
|
692
731
|
attempts.append(
|
|
@@ -704,7 +743,7 @@ class HistoryManager:
|
|
|
704
743
|
platform_machine=row["platform_machine"],
|
|
705
744
|
submitted_to_dockstore=(row["submitted_to_dockstore"] == 1),
|
|
706
745
|
workflow_job_store=row["workflow_job_store"],
|
|
707
|
-
workflow_trs_spec=row["workflow_trs_spec"]
|
|
746
|
+
workflow_trs_spec=row["workflow_trs_spec"],
|
|
708
747
|
)
|
|
709
748
|
)
|
|
710
749
|
except:
|
|
@@ -719,7 +758,9 @@ class HistoryManager:
|
|
|
719
758
|
|
|
720
759
|
@classmethod
|
|
721
760
|
@db_retry
|
|
722
|
-
def get_workflow_attempts_with_submittable_job_attempts(
|
|
761
|
+
def get_workflow_attempts_with_submittable_job_attempts(
|
|
762
|
+
cls, limit: int = sys.maxsize
|
|
763
|
+
) -> list[WorkflowAttemptSummary]:
|
|
723
764
|
"""
|
|
724
765
|
Get all workflow attempts that have job attempts not yet submitted to
|
|
725
766
|
Dockstore.
|
|
@@ -769,7 +810,7 @@ class HistoryManager:
|
|
|
769
810
|
WHERE workflows.trs_spec IS NOT NULL
|
|
770
811
|
LIMIT ?
|
|
771
812
|
""",
|
|
772
|
-
(limit,)
|
|
813
|
+
(limit,),
|
|
773
814
|
)
|
|
774
815
|
for row in cur:
|
|
775
816
|
# TODO: Unify row to data class conversion
|
|
@@ -788,7 +829,7 @@ class HistoryManager:
|
|
|
788
829
|
platform_machine=row["platform_machine"],
|
|
789
830
|
submitted_to_dockstore=(row["submitted_to_dockstore"] == 1),
|
|
790
831
|
workflow_job_store=row["workflow_job_store"],
|
|
791
|
-
workflow_trs_spec=row["workflow_trs_spec"]
|
|
832
|
+
workflow_trs_spec=row["workflow_trs_spec"],
|
|
792
833
|
)
|
|
793
834
|
)
|
|
794
835
|
except:
|
|
@@ -803,7 +844,9 @@ class HistoryManager:
|
|
|
803
844
|
|
|
804
845
|
@classmethod
|
|
805
846
|
@db_retry
|
|
806
|
-
def get_workflow_attempt(
|
|
847
|
+
def get_workflow_attempt(
|
|
848
|
+
cls, workflow_id: str, attempt_number: int
|
|
849
|
+
) -> WorkflowAttemptSummary | None:
|
|
807
850
|
"""
|
|
808
851
|
Get a single (not necessarily unsubmitted, not necessarily TRS-ID-having) workflow attempt summary, if present.
|
|
809
852
|
"""
|
|
@@ -843,7 +886,7 @@ class HistoryManager:
|
|
|
843
886
|
ORDER BY start_time DESC
|
|
844
887
|
LIMIT 1
|
|
845
888
|
""",
|
|
846
|
-
(workflow_id, attempt_number)
|
|
889
|
+
(workflow_id, attempt_number),
|
|
847
890
|
)
|
|
848
891
|
for row in cur:
|
|
849
892
|
attempts.append(
|
|
@@ -861,7 +904,7 @@ class HistoryManager:
|
|
|
861
904
|
platform_machine=row["platform_machine"],
|
|
862
905
|
submitted_to_dockstore=(row["submitted_to_dockstore"] == 1),
|
|
863
906
|
workflow_job_store=row["workflow_job_store"],
|
|
864
|
-
workflow_trs_spec=row["workflow_trs_spec"]
|
|
907
|
+
workflow_trs_spec=row["workflow_trs_spec"],
|
|
865
908
|
)
|
|
866
909
|
)
|
|
867
910
|
except:
|
|
@@ -880,7 +923,9 @@ class HistoryManager:
|
|
|
880
923
|
|
|
881
924
|
@classmethod
|
|
882
925
|
@db_retry
|
|
883
|
-
def get_unsubmitted_job_attempts(
|
|
926
|
+
def get_unsubmitted_job_attempts(
|
|
927
|
+
cls, workflow_id: str, attempt_number: int
|
|
928
|
+
) -> list[JobAttemptSummary]:
|
|
884
929
|
"""
|
|
885
930
|
List all job attempts in the given workflow attempt not yet submitted to Dockstore.
|
|
886
931
|
|
|
@@ -915,7 +960,7 @@ class HistoryManager:
|
|
|
915
960
|
AND submitted_to_dockstore = FALSE
|
|
916
961
|
ORDER BY start_time DESC
|
|
917
962
|
""",
|
|
918
|
-
(workflow_id, attempt_number)
|
|
963
|
+
(workflow_id, attempt_number),
|
|
919
964
|
)
|
|
920
965
|
for row in cur:
|
|
921
966
|
attempts.append(
|
|
@@ -929,7 +974,7 @@ class HistoryManager:
|
|
|
929
974
|
cpu_seconds=row["cpu_seconds"],
|
|
930
975
|
memory_bytes=row["memory_bytes"],
|
|
931
976
|
disk_bytes=row["disk_bytes"],
|
|
932
|
-
submitted_to_dockstore=(row["submitted_to_dockstore"] == 1)
|
|
977
|
+
submitted_to_dockstore=(row["submitted_to_dockstore"] == 1),
|
|
933
978
|
)
|
|
934
979
|
)
|
|
935
980
|
except:
|
|
@@ -948,7 +993,9 @@ class HistoryManager:
|
|
|
948
993
|
|
|
949
994
|
@classmethod
|
|
950
995
|
@db_retry
|
|
951
|
-
def mark_workflow_attempt_submitted(
|
|
996
|
+
def mark_workflow_attempt_submitted(
|
|
997
|
+
cls, workflow_id: str, attempt_number: int
|
|
998
|
+
) -> None:
|
|
952
999
|
"""
|
|
953
1000
|
Mark a workflow attempt as having been successfully submitted to Dockstore.
|
|
954
1001
|
|
|
@@ -964,7 +1011,7 @@ class HistoryManager:
|
|
|
964
1011
|
cls.ensure_tables(con, cur)
|
|
965
1012
|
cur.execute(
|
|
966
1013
|
"UPDATE workflow_attempts SET submitted_to_dockstore = TRUE WHERE workflow_id = ? AND attempt_number = ?",
|
|
967
|
-
(workflow_id, attempt_number)
|
|
1014
|
+
(workflow_id, attempt_number),
|
|
968
1015
|
)
|
|
969
1016
|
except:
|
|
970
1017
|
con.rollback()
|
|
@@ -992,7 +1039,7 @@ class HistoryManager:
|
|
|
992
1039
|
# Do all the marking in one transaction
|
|
993
1040
|
cur.execute(
|
|
994
1041
|
"UPDATE job_attempts SET submitted_to_dockstore = TRUE WHERE id = ?",
|
|
995
|
-
(job_attempt_id,)
|
|
1042
|
+
(job_attempt_id,),
|
|
996
1043
|
)
|
|
997
1044
|
except:
|
|
998
1045
|
con.rollback()
|
|
@@ -1008,7 +1055,7 @@ class HistoryManager:
|
|
|
1008
1055
|
"""
|
|
1009
1056
|
Count workflows in the database.
|
|
1010
1057
|
"""
|
|
1011
|
-
|
|
1058
|
+
|
|
1012
1059
|
if not cls.enabled():
|
|
1013
1060
|
return 0
|
|
1014
1061
|
|
|
@@ -1139,7 +1186,7 @@ class HistoryManager:
|
|
|
1139
1186
|
) = 0
|
|
1140
1187
|
LIMIT ?
|
|
1141
1188
|
""",
|
|
1142
|
-
(limit,)
|
|
1189
|
+
(limit,),
|
|
1143
1190
|
)
|
|
1144
1191
|
for row in cur:
|
|
1145
1192
|
ids.append(row["id"])
|
|
@@ -1185,7 +1232,7 @@ class HistoryManager:
|
|
|
1185
1232
|
ORDER BY creation_time ASC
|
|
1186
1233
|
LIMIT ?
|
|
1187
1234
|
""",
|
|
1188
|
-
(limit,)
|
|
1235
|
+
(limit,),
|
|
1189
1236
|
)
|
|
1190
1237
|
for row in cur:
|
|
1191
1238
|
ids.append(row["id"])
|
|
@@ -1216,8 +1263,12 @@ class HistoryManager:
|
|
|
1216
1263
|
try:
|
|
1217
1264
|
cls.ensure_tables(con, cur)
|
|
1218
1265
|
|
|
1219
|
-
cur.execute(
|
|
1220
|
-
|
|
1266
|
+
cur.execute(
|
|
1267
|
+
"DELETE FROM job_attempts WHERE workflow_id = ?", (workflow_id,)
|
|
1268
|
+
)
|
|
1269
|
+
cur.execute(
|
|
1270
|
+
"DELETE FROM workflow_attempts WHERE workflow_id = ?", (workflow_id,)
|
|
1271
|
+
)
|
|
1221
1272
|
cur.execute("DELETE FROM workflows WHERE id = ?", (workflow_id,))
|
|
1222
1273
|
except:
|
|
1223
1274
|
con.rollback()
|
|
@@ -1269,13 +1320,13 @@ class HistoryManager:
|
|
|
1269
1320
|
|
|
1270
1321
|
if not cls.enabled():
|
|
1271
1322
|
return
|
|
1272
|
-
|
|
1323
|
+
|
|
1273
1324
|
con = cls.connection()
|
|
1274
1325
|
cur = con.cursor()
|
|
1275
1326
|
|
|
1276
1327
|
# Don't bother making tables; we don't need them for this and they need
|
|
1277
1328
|
# a transaction.
|
|
1278
|
-
|
|
1329
|
+
|
|
1279
1330
|
with cls.no_transaction(con):
|
|
1280
1331
|
# Do the vacuum outside any transaction, and rely on it to
|
|
1281
1332
|
# synchronize appropriately internally.
|
|
@@ -1324,9 +1375,6 @@ class HistoryManager:
|
|
|
1324
1375
|
# Re-check the size
|
|
1325
1376
|
db_size = cls.get_database_byte_size()
|
|
1326
1377
|
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
1378
|
@classmethod
|
|
1331
1379
|
def database_dump_lines(cls) -> Iterable[str]:
|
|
1332
1380
|
"""
|
|
@@ -1339,7 +1387,3 @@ class HistoryManager:
|
|
|
1339
1387
|
return []
|
|
1340
1388
|
|
|
1341
1389
|
return cls.connection().iterdump()
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|