toil 6.1.0a1__py3-none-any.whl → 8.0.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 +122 -315
- toil/batchSystems/__init__.py +1 -0
- toil/batchSystems/abstractBatchSystem.py +173 -89
- toil/batchSystems/abstractGridEngineBatchSystem.py +272 -148
- toil/batchSystems/awsBatch.py +244 -135
- toil/batchSystems/cleanup_support.py +26 -16
- toil/batchSystems/contained_executor.py +31 -28
- toil/batchSystems/gridengine.py +86 -50
- toil/batchSystems/htcondor.py +166 -89
- toil/batchSystems/kubernetes.py +632 -382
- toil/batchSystems/local_support.py +20 -15
- toil/batchSystems/lsf.py +134 -81
- toil/batchSystems/lsfHelper.py +13 -11
- toil/batchSystems/mesos/__init__.py +41 -29
- toil/batchSystems/mesos/batchSystem.py +290 -151
- toil/batchSystems/mesos/executor.py +79 -50
- toil/batchSystems/mesos/test/__init__.py +31 -23
- toil/batchSystems/options.py +46 -28
- toil/batchSystems/registry.py +53 -19
- toil/batchSystems/singleMachine.py +296 -125
- toil/batchSystems/slurm.py +603 -138
- toil/batchSystems/torque.py +47 -33
- toil/bus.py +186 -76
- toil/common.py +664 -368
- toil/cwl/__init__.py +1 -1
- toil/cwl/cwltoil.py +1136 -483
- toil/cwl/utils.py +17 -22
- toil/deferred.py +63 -42
- toil/exceptions.py +5 -3
- toil/fileStores/__init__.py +5 -5
- toil/fileStores/abstractFileStore.py +140 -60
- toil/fileStores/cachingFileStore.py +717 -269
- toil/fileStores/nonCachingFileStore.py +116 -87
- toil/job.py +1225 -368
- toil/jobStores/abstractJobStore.py +416 -266
- toil/jobStores/aws/jobStore.py +863 -477
- toil/jobStores/aws/utils.py +201 -120
- toil/jobStores/conftest.py +3 -2
- toil/jobStores/fileJobStore.py +292 -154
- toil/jobStores/googleJobStore.py +140 -74
- toil/jobStores/utils.py +36 -15
- toil/leader.py +668 -272
- toil/lib/accelerators.py +115 -18
- toil/lib/aws/__init__.py +74 -31
- toil/lib/aws/ami.py +122 -87
- toil/lib/aws/iam.py +284 -108
- toil/lib/aws/s3.py +31 -0
- toil/lib/aws/session.py +214 -39
- toil/lib/aws/utils.py +287 -231
- toil/lib/bioio.py +13 -5
- toil/lib/compatibility.py +11 -6
- toil/lib/conversions.py +104 -47
- toil/lib/docker.py +131 -103
- toil/lib/ec2.py +361 -199
- toil/lib/ec2nodes.py +174 -106
- toil/lib/encryption/_dummy.py +5 -3
- toil/lib/encryption/_nacl.py +10 -6
- toil/lib/encryption/conftest.py +1 -0
- toil/lib/exceptions.py +26 -7
- toil/lib/expando.py +5 -3
- toil/lib/ftp_utils.py +217 -0
- toil/lib/generatedEC2Lists.py +127 -19
- toil/lib/humanize.py +6 -2
- toil/lib/integration.py +341 -0
- toil/lib/io.py +141 -15
- toil/lib/iterables.py +4 -2
- toil/lib/memoize.py +12 -8
- toil/lib/misc.py +66 -21
- toil/lib/objects.py +2 -2
- toil/lib/resources.py +68 -15
- toil/lib/retry.py +126 -81
- toil/lib/threading.py +299 -82
- toil/lib/throttle.py +16 -15
- toil/options/common.py +843 -409
- toil/options/cwl.py +175 -90
- toil/options/runner.py +50 -0
- toil/options/wdl.py +73 -17
- toil/provisioners/__init__.py +117 -46
- toil/provisioners/abstractProvisioner.py +332 -157
- toil/provisioners/aws/__init__.py +70 -33
- toil/provisioners/aws/awsProvisioner.py +1145 -715
- toil/provisioners/clusterScaler.py +541 -279
- toil/provisioners/gceProvisioner.py +282 -179
- toil/provisioners/node.py +155 -79
- toil/realtimeLogger.py +34 -22
- toil/resource.py +137 -75
- toil/server/app.py +128 -62
- toil/server/celery_app.py +3 -1
- toil/server/cli/wes_cwl_runner.py +82 -53
- toil/server/utils.py +54 -28
- toil/server/wes/abstract_backend.py +64 -26
- toil/server/wes/amazon_wes_utils.py +21 -15
- toil/server/wes/tasks.py +121 -63
- toil/server/wes/toil_backend.py +142 -107
- toil/server/wsgi_app.py +4 -3
- toil/serviceManager.py +58 -22
- toil/statsAndLogging.py +224 -70
- toil/test/__init__.py +282 -183
- toil/test/batchSystems/batchSystemTest.py +460 -210
- toil/test/batchSystems/batch_system_plugin_test.py +90 -0
- toil/test/batchSystems/test_gridengine.py +173 -0
- toil/test/batchSystems/test_lsf_helper.py +67 -58
- toil/test/batchSystems/test_slurm.py +110 -49
- toil/test/cactus/__init__.py +0 -0
- toil/test/cactus/test_cactus_integration.py +56 -0
- toil/test/cwl/cwlTest.py +496 -287
- toil/test/cwl/measure_default_memory.cwl +12 -0
- toil/test/cwl/not_run_required_input.cwl +29 -0
- toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
- toil/test/cwl/seqtk_seq.cwl +1 -1
- toil/test/docs/scriptsTest.py +69 -46
- toil/test/jobStores/jobStoreTest.py +427 -264
- toil/test/lib/aws/test_iam.py +118 -50
- toil/test/lib/aws/test_s3.py +16 -9
- toil/test/lib/aws/test_utils.py +5 -6
- toil/test/lib/dockerTest.py +118 -141
- toil/test/lib/test_conversions.py +113 -115
- toil/test/lib/test_ec2.py +58 -50
- toil/test/lib/test_integration.py +104 -0
- toil/test/lib/test_misc.py +12 -5
- toil/test/mesos/MesosDataStructuresTest.py +23 -10
- toil/test/mesos/helloWorld.py +7 -6
- toil/test/mesos/stress.py +25 -20
- toil/test/options/__init__.py +13 -0
- toil/test/options/options.py +42 -0
- toil/test/provisioners/aws/awsProvisionerTest.py +320 -150
- toil/test/provisioners/clusterScalerTest.py +440 -250
- toil/test/provisioners/clusterTest.py +166 -44
- toil/test/provisioners/gceProvisionerTest.py +174 -100
- toil/test/provisioners/provisionerTest.py +25 -13
- toil/test/provisioners/restartScript.py +5 -4
- toil/test/server/serverTest.py +188 -141
- toil/test/sort/restart_sort.py +137 -68
- toil/test/sort/sort.py +134 -66
- toil/test/sort/sortTest.py +91 -49
- toil/test/src/autoDeploymentTest.py +141 -101
- toil/test/src/busTest.py +20 -18
- toil/test/src/checkpointTest.py +8 -2
- toil/test/src/deferredFunctionTest.py +49 -35
- toil/test/src/dockerCheckTest.py +32 -24
- toil/test/src/environmentTest.py +135 -0
- toil/test/src/fileStoreTest.py +539 -272
- toil/test/src/helloWorldTest.py +7 -4
- toil/test/src/importExportFileTest.py +61 -31
- toil/test/src/jobDescriptionTest.py +46 -21
- toil/test/src/jobEncapsulationTest.py +2 -0
- toil/test/src/jobFileStoreTest.py +74 -50
- toil/test/src/jobServiceTest.py +187 -73
- toil/test/src/jobTest.py +121 -71
- toil/test/src/miscTests.py +19 -18
- toil/test/src/promisedRequirementTest.py +82 -36
- toil/test/src/promisesTest.py +7 -6
- toil/test/src/realtimeLoggerTest.py +10 -6
- toil/test/src/regularLogTest.py +71 -37
- toil/test/src/resourceTest.py +80 -49
- toil/test/src/restartDAGTest.py +36 -22
- toil/test/src/resumabilityTest.py +9 -2
- toil/test/src/retainTempDirTest.py +45 -14
- toil/test/src/systemTest.py +12 -8
- toil/test/src/threadingTest.py +44 -25
- toil/test/src/toilContextManagerTest.py +10 -7
- toil/test/src/userDefinedJobArgTypeTest.py +8 -5
- toil/test/src/workerTest.py +73 -23
- toil/test/utils/toilDebugTest.py +103 -33
- toil/test/utils/toilKillTest.py +4 -5
- toil/test/utils/utilsTest.py +245 -106
- toil/test/wdl/wdltoil_test.py +818 -149
- toil/test/wdl/wdltoil_test_kubernetes.py +91 -0
- toil/toilState.py +120 -35
- toil/utils/toilConfig.py +13 -4
- toil/utils/toilDebugFile.py +44 -27
- toil/utils/toilDebugJob.py +214 -27
- toil/utils/toilDestroyCluster.py +11 -6
- toil/utils/toilKill.py +8 -3
- toil/utils/toilLaunchCluster.py +256 -140
- toil/utils/toilMain.py +37 -16
- toil/utils/toilRsyncCluster.py +32 -14
- toil/utils/toilSshCluster.py +49 -22
- toil/utils/toilStats.py +356 -273
- toil/utils/toilStatus.py +292 -139
- toil/utils/toilUpdateEC2Instances.py +3 -1
- toil/version.py +12 -12
- toil/wdl/utils.py +5 -5
- toil/wdl/wdltoil.py +3913 -1033
- toil/worker.py +367 -184
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/LICENSE +25 -0
- toil-8.0.0.dist-info/METADATA +173 -0
- toil-8.0.0.dist-info/RECORD +253 -0
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/WHEEL +1 -1
- toil-6.1.0a1.dist-info/METADATA +0 -125
- toil-6.1.0a1.dist-info/RECORD +0 -237
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/entry_points.txt +0 -0
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/top_level.txt +0 -0
toil/test/src/jobServiceTest.py
CHANGED
|
@@ -46,10 +46,10 @@ class JobServiceTest(ToilTest):
|
|
|
46
46
|
"""
|
|
47
47
|
job = Job()
|
|
48
48
|
service = ToySerializableService("woot")
|
|
49
|
-
startValue = job.addService(service)
|
|
50
|
-
subService = ToySerializableService(startValue)
|
|
49
|
+
startValue = job.addService(service) # Add a first service to job
|
|
50
|
+
subService = ToySerializableService(startValue) # Now create a child of
|
|
51
51
|
# that service that takes the start value promise from the parent service
|
|
52
|
-
job.addService(subService, parentService=service)
|
|
52
|
+
job.addService(subService, parentService=service) # This should work if
|
|
53
53
|
# serialization on services is working correctly.
|
|
54
54
|
|
|
55
55
|
self.runToil(job)
|
|
@@ -60,11 +60,13 @@ class JobServiceTest(ToilTest):
|
|
|
60
60
|
Tests the creation of a Job.Service with random failures of the worker.
|
|
61
61
|
"""
|
|
62
62
|
for test in range(2):
|
|
63
|
-
outFile = get_temp_file(rootDir=self._createTempDir())
|
|
63
|
+
outFile = get_temp_file(rootDir=self._createTempDir()) # Temporary file
|
|
64
64
|
messageInt = random.randint(1, sys.maxsize)
|
|
65
65
|
try:
|
|
66
66
|
# Wire up the services/jobs
|
|
67
|
-
t = Job.wrapJobFn(
|
|
67
|
+
t = Job.wrapJobFn(
|
|
68
|
+
serviceTest, outFile, messageInt, checkpoint=checkpoint
|
|
69
|
+
)
|
|
68
70
|
|
|
69
71
|
# Run the workflow repeatedly until success
|
|
70
72
|
self.runToil(t)
|
|
@@ -75,24 +77,30 @@ class JobServiceTest(ToilTest):
|
|
|
75
77
|
os.remove(outFile)
|
|
76
78
|
|
|
77
79
|
@slow
|
|
78
|
-
@skipIf(
|
|
80
|
+
@skipIf(
|
|
81
|
+
SingleMachineBatchSystem.numCores < 4,
|
|
82
|
+
"Need at least four cores to run this test",
|
|
83
|
+
)
|
|
79
84
|
def testServiceDeadlock(self):
|
|
80
85
|
"""
|
|
81
86
|
Creates a job with more services than maxServices, checks that deadlock is detected.
|
|
82
87
|
"""
|
|
83
88
|
outFile = get_temp_file(rootDir=self._createTempDir())
|
|
84
89
|
try:
|
|
90
|
+
|
|
85
91
|
def makeWorkflow():
|
|
86
92
|
job = Job()
|
|
87
93
|
r1 = job.addService(ToySerializableService("woot1"))
|
|
88
94
|
r2 = job.addService(ToySerializableService("woot2"))
|
|
89
95
|
r3 = job.addService(ToySerializableService("woot3"))
|
|
90
|
-
job.addChildFn(fnTest, [
|
|
96
|
+
job.addChildFn(fnTest, [r1, r2, r3], outFile)
|
|
91
97
|
return job
|
|
92
98
|
|
|
93
99
|
# This should fail as too few services available
|
|
94
100
|
try:
|
|
95
|
-
self.runToil(
|
|
101
|
+
self.runToil(
|
|
102
|
+
makeWorkflow(), badWorker=0.0, maxServiceJobs=2, deadlockWait=5
|
|
103
|
+
)
|
|
96
104
|
except DeadlockException:
|
|
97
105
|
print("Got expected deadlock exception")
|
|
98
106
|
else:
|
|
@@ -113,7 +121,10 @@ class JobServiceTest(ToilTest):
|
|
|
113
121
|
self.testService(checkpoint=True)
|
|
114
122
|
|
|
115
123
|
@slow
|
|
116
|
-
@skipIf(
|
|
124
|
+
@skipIf(
|
|
125
|
+
SingleMachineBatchSystem.numCores < 4,
|
|
126
|
+
"Need at least four cores to run this test",
|
|
127
|
+
)
|
|
117
128
|
def testServiceRecursive(self, checkpoint=True):
|
|
118
129
|
"""
|
|
119
130
|
Tests the creation of a Job.Service, creating a chain of services and accessing jobs.
|
|
@@ -122,10 +133,12 @@ class JobServiceTest(ToilTest):
|
|
|
122
133
|
for test in range(1):
|
|
123
134
|
# Temporary file
|
|
124
135
|
outFile = get_temp_file(rootDir=self._createTempDir())
|
|
125
|
-
messages = [
|
|
136
|
+
messages = [random.randint(1, sys.maxsize) for i in range(3)]
|
|
126
137
|
try:
|
|
127
138
|
# Wire up the services/jobs
|
|
128
|
-
t = Job.wrapJobFn(
|
|
139
|
+
t = Job.wrapJobFn(
|
|
140
|
+
serviceTestRecursive, outFile, messages, checkpoint=checkpoint
|
|
141
|
+
)
|
|
129
142
|
|
|
130
143
|
# Run the workflow repeatedly until success
|
|
131
144
|
self.runToil(t)
|
|
@@ -136,32 +149,76 @@ class JobServiceTest(ToilTest):
|
|
|
136
149
|
os.remove(outFile)
|
|
137
150
|
|
|
138
151
|
@slow
|
|
139
|
-
@skipIf(
|
|
140
|
-
|
|
152
|
+
@skipIf(
|
|
153
|
+
SingleMachineBatchSystem.numCores < 4,
|
|
154
|
+
"Need at least four cores to run this test",
|
|
155
|
+
)
|
|
141
156
|
@pytest.mark.timeout(1200)
|
|
142
157
|
def testServiceParallelRecursive(self, checkpoint=True):
|
|
143
158
|
"""
|
|
144
159
|
Tests the creation of a Job.Service, creating parallel chains of services and accessing jobs.
|
|
145
160
|
Randomly fails the worker.
|
|
146
161
|
"""
|
|
162
|
+
|
|
163
|
+
# This test needs to have something like 10 jobs succeed
|
|
164
|
+
|
|
165
|
+
BUNDLE_SIZE = 3
|
|
166
|
+
BUNDLE_COUNT = 2
|
|
167
|
+
RETRY_COUNT = 4
|
|
168
|
+
FAIL_FRACTION = 0.5
|
|
169
|
+
MAX_ATTEMPTS = 10
|
|
170
|
+
|
|
171
|
+
total_jobs = BUNDLE_SIZE * BUNDLE_COUNT * 2 + 1
|
|
172
|
+
p_complete_job_failure = FAIL_FRACTION ** (RETRY_COUNT + 1)
|
|
173
|
+
p_workflow_success = (1 - p_complete_job_failure) ** total_jobs
|
|
174
|
+
logger.info("Going to run %s total jobs, each of which completely fails %s of the time, so the workflow will succeed with probability %s", total_jobs, p_complete_job_failure, p_workflow_success)
|
|
175
|
+
p_test_failure = (1 - p_workflow_success) ** MAX_ATTEMPTS
|
|
176
|
+
logger.info("This test will fail spuriously with probability %s", p_test_failure)
|
|
177
|
+
|
|
178
|
+
# We want to run the workflow through several times to test restarting, so we need it to often fail but reliably sometimes succeed, and almost always succeed when repeated.
|
|
179
|
+
|
|
180
|
+
self.assertGreater(0.8, p_workflow_success)
|
|
181
|
+
self.assertGreater(p_workflow_success, 0.2)
|
|
182
|
+
self.assertGreater(0.001, p_test_failure)
|
|
183
|
+
|
|
184
|
+
|
|
147
185
|
for test in range(1):
|
|
148
186
|
# Temporary file
|
|
149
|
-
outFiles = [get_temp_file(rootDir=self._createTempDir()) for j in range(
|
|
150
|
-
|
|
187
|
+
outFiles = [get_temp_file(rootDir=self._createTempDir()) for j in range(BUNDLE_COUNT)]
|
|
188
|
+
# We send 3 messages each in 2 sets, each of which needs a service and a client
|
|
189
|
+
messageBundles = [
|
|
190
|
+
[random.randint(1, sys.maxsize) for i in range(BUNDLE_SIZE)] for j in range(BUNDLE_COUNT)
|
|
191
|
+
]
|
|
151
192
|
try:
|
|
152
193
|
# Wire up the services/jobs
|
|
153
|
-
t = Job.wrapJobFn(
|
|
194
|
+
t = Job.wrapJobFn(
|
|
195
|
+
serviceTestParallelRecursive,
|
|
196
|
+
outFiles,
|
|
197
|
+
messageBundles,
|
|
198
|
+
checkpoint=True,
|
|
199
|
+
)
|
|
154
200
|
|
|
155
201
|
# Run the workflow repeatedly until success
|
|
156
|
-
self.runToil(t, retryCount=
|
|
202
|
+
self.runToil(t, retryCount=RETRY_COUNT, badWorker=FAIL_FRACTION, max_attempts=MAX_ATTEMPTS)
|
|
157
203
|
|
|
158
204
|
# Check output
|
|
159
|
-
for
|
|
160
|
-
self.assertEqual(
|
|
205
|
+
for messages, outFile in zip(messageBundles, outFiles):
|
|
206
|
+
self.assertEqual(
|
|
207
|
+
list(map(int, open(outFile).readlines())), messages
|
|
208
|
+
)
|
|
161
209
|
finally:
|
|
162
210
|
list(map(os.remove, outFiles))
|
|
163
211
|
|
|
164
|
-
def runToil(
|
|
212
|
+
def runToil(
|
|
213
|
+
self,
|
|
214
|
+
rootJob,
|
|
215
|
+
retryCount=1,
|
|
216
|
+
badWorker=0.5,
|
|
217
|
+
badWorkedFailInterval=0.1,
|
|
218
|
+
maxServiceJobs=sys.maxsize,
|
|
219
|
+
deadlockWait=60,
|
|
220
|
+
max_attempts=50
|
|
221
|
+
):
|
|
165
222
|
# Create the runner for the workflow.
|
|
166
223
|
options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
|
|
167
224
|
options.logLevel = "DEBUG"
|
|
@@ -171,27 +228,38 @@ class JobServiceTest(ToilTest):
|
|
|
171
228
|
options.badWorkerFailInterval = badWorkedFailInterval
|
|
172
229
|
options.servicePollingInterval = 1
|
|
173
230
|
options.maxServiceJobs = maxServiceJobs
|
|
174
|
-
options.deadlockWait=deadlockWait
|
|
231
|
+
options.deadlockWait = deadlockWait
|
|
175
232
|
|
|
176
233
|
# Run the workflow
|
|
177
|
-
|
|
234
|
+
total_tries = 1
|
|
178
235
|
while True:
|
|
179
236
|
try:
|
|
180
237
|
Job.Runner.startToil(rootJob, options)
|
|
181
238
|
break
|
|
182
239
|
except FailedJobsException as e:
|
|
183
240
|
i = e.numberOfFailedJobs
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
241
|
+
logger.info("Workflow attempt %s/%s failed with %s failed jobs", total_tries, max_attempts, i)
|
|
242
|
+
if total_tries == max_attempts:
|
|
243
|
+
self.fail() # Exceeded a reasonable number of restarts
|
|
244
|
+
total_tries += 1
|
|
187
245
|
options.restart = True
|
|
246
|
+
logger.info("Succeeded after %s/%s attempts", total_tries, max_attempts)
|
|
247
|
+
|
|
188
248
|
|
|
189
249
|
class PerfectServiceTest(JobServiceTest):
|
|
190
|
-
def runToil(
|
|
250
|
+
def runToil(
|
|
251
|
+
self,
|
|
252
|
+
*args,
|
|
253
|
+
**kwargs
|
|
254
|
+
):
|
|
191
255
|
"""
|
|
192
256
|
Let us run all the tests in the other service test class, but without worker failures.
|
|
193
257
|
"""
|
|
194
|
-
|
|
258
|
+
kwargs["badWorker"] = 0
|
|
259
|
+
super().runToil(
|
|
260
|
+
*args,
|
|
261
|
+
**kwargs
|
|
262
|
+
)
|
|
195
263
|
|
|
196
264
|
|
|
197
265
|
def serviceTest(job, outFile, messageInt):
|
|
@@ -199,51 +267,76 @@ def serviceTest(job, outFile, messageInt):
|
|
|
199
267
|
Creates one service and one accessing job, which communicate with two files to establish
|
|
200
268
|
that both run concurrently.
|
|
201
269
|
"""
|
|
202
|
-
#Clean out out-file
|
|
203
|
-
open(outFile,
|
|
204
|
-
|
|
205
|
-
#
|
|
206
|
-
|
|
270
|
+
# Clean out out-file
|
|
271
|
+
open(outFile, "w").close()
|
|
272
|
+
# We create a random number that is added to messageInt and subtracted by
|
|
273
|
+
# the serviceAccessor, to prove that when service test is checkpointed and
|
|
274
|
+
# restarted there is never a connection made between an earlier service and
|
|
275
|
+
# later serviceAccessor, or vice versa.
|
|
276
|
+
to_subtract = random.randint(
|
|
277
|
+
1, sys.maxsize
|
|
278
|
+
)
|
|
279
|
+
job.addChildJobFn(
|
|
280
|
+
serviceAccessor,
|
|
281
|
+
job.addService(ToyService(messageInt + to_subtract)),
|
|
282
|
+
outFile,
|
|
283
|
+
to_subtract,
|
|
284
|
+
)
|
|
285
|
+
|
|
207
286
|
|
|
208
287
|
def serviceTestRecursive(job, outFile, messages):
|
|
209
288
|
"""
|
|
210
289
|
Creates a chain of services and accessing jobs, each paired together.
|
|
211
290
|
"""
|
|
212
291
|
if len(messages) > 0:
|
|
213
|
-
#Clean out out-file
|
|
214
|
-
open(outFile,
|
|
215
|
-
|
|
216
|
-
service = ToyService(messages[0] +
|
|
217
|
-
child = job.addChildJobFn(
|
|
292
|
+
# Clean out out-file
|
|
293
|
+
open(outFile, "w").close()
|
|
294
|
+
to_add = random.randint(1, sys.maxsize)
|
|
295
|
+
service = ToyService(messages[0] + to_add)
|
|
296
|
+
child = job.addChildJobFn(
|
|
297
|
+
serviceAccessor, job.addService(service), outFile, to_add
|
|
298
|
+
)
|
|
218
299
|
|
|
219
300
|
for i in range(1, len(messages)):
|
|
220
|
-
|
|
221
|
-
service2 = ToyService(messages[i] +
|
|
222
|
-
child = child.addChildJobFn(
|
|
223
|
-
|
|
224
|
-
|
|
301
|
+
to_add = random.randint(1, sys.maxsize)
|
|
302
|
+
service2 = ToyService(messages[i] + to_add, cores=0.1)
|
|
303
|
+
child = child.addChildJobFn(
|
|
304
|
+
serviceAccessor,
|
|
305
|
+
job.addService(service2, parentService=service),
|
|
306
|
+
outFile,
|
|
307
|
+
to_add,
|
|
308
|
+
cores=0.1,
|
|
309
|
+
)
|
|
225
310
|
service = service2
|
|
226
311
|
|
|
312
|
+
|
|
227
313
|
def serviceTestParallelRecursive(job, outFiles, messageBundles):
|
|
228
314
|
"""
|
|
229
315
|
Creates multiple chains of services and accessing jobs.
|
|
230
316
|
"""
|
|
231
317
|
for messages, outFile in zip(messageBundles, outFiles):
|
|
232
|
-
#Clean out out-file
|
|
233
|
-
open(outFile,
|
|
318
|
+
# Clean out out-file
|
|
319
|
+
open(outFile, "w").close()
|
|
234
320
|
if len(messages) > 0:
|
|
235
|
-
|
|
236
|
-
service = ToyService(messages[0] +
|
|
237
|
-
child = job.addChildJobFn(
|
|
321
|
+
to_add = random.randint(1, sys.maxsize)
|
|
322
|
+
service = ToyService(messages[0] + to_add)
|
|
323
|
+
child = job.addChildJobFn(
|
|
324
|
+
serviceAccessor, job.addService(service), outFile, to_add
|
|
325
|
+
)
|
|
238
326
|
|
|
239
327
|
for i in range(1, len(messages)):
|
|
240
|
-
|
|
241
|
-
service2 = ToyService(messages[i] +
|
|
242
|
-
child = child.addChildJobFn(
|
|
243
|
-
|
|
244
|
-
|
|
328
|
+
to_add = random.randint(1, sys.maxsize)
|
|
329
|
+
service2 = ToyService(messages[i] + to_add, cores=0.1)
|
|
330
|
+
child = child.addChildJobFn(
|
|
331
|
+
serviceAccessor,
|
|
332
|
+
job.addService(service2, parentService=service),
|
|
333
|
+
outFile,
|
|
334
|
+
to_add,
|
|
335
|
+
cores=0.1,
|
|
336
|
+
)
|
|
245
337
|
service = service2
|
|
246
338
|
|
|
339
|
+
|
|
247
340
|
class ToyService(Job.Service):
|
|
248
341
|
def __init__(self, messageInt, *args, **kwargs):
|
|
249
342
|
"""
|
|
@@ -264,10 +357,17 @@ class ToyService(Job.Service):
|
|
|
264
357
|
# So we don't associate these files with this job.
|
|
265
358
|
inJobStoreID = job.fileStore.jobStore.get_empty_file_store_id()
|
|
266
359
|
outJobStoreID = job.fileStore.jobStore.get_empty_file_store_id()
|
|
267
|
-
self.serviceThread = Thread(
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
360
|
+
self.serviceThread = Thread(
|
|
361
|
+
target=self.serviceWorker,
|
|
362
|
+
args=(
|
|
363
|
+
job.fileStore.jobStore,
|
|
364
|
+
self.terminate,
|
|
365
|
+
self.error,
|
|
366
|
+
inJobStoreID,
|
|
367
|
+
outJobStoreID,
|
|
368
|
+
self.messageInt,
|
|
369
|
+
),
|
|
370
|
+
)
|
|
271
371
|
self.serviceThread.start()
|
|
272
372
|
return (inJobStoreID, outJobStoreID)
|
|
273
373
|
|
|
@@ -281,22 +381,27 @@ class ToyService(Job.Service):
|
|
|
281
381
|
return True
|
|
282
382
|
|
|
283
383
|
@staticmethod
|
|
284
|
-
def serviceWorker(
|
|
384
|
+
def serviceWorker(
|
|
385
|
+
jobStore, terminate, error, inJobStoreID, outJobStoreID, messageInt
|
|
386
|
+
):
|
|
285
387
|
try:
|
|
286
388
|
while True:
|
|
287
|
-
if terminate.isSet():
|
|
389
|
+
if terminate.isSet(): # Quit if we've got the terminate signal
|
|
288
390
|
logger.debug("Service worker being told to quit")
|
|
289
391
|
return
|
|
290
392
|
|
|
291
|
-
time.sleep(0.2)
|
|
393
|
+
time.sleep(0.2) # Sleep to avoid thrashing
|
|
292
394
|
|
|
293
395
|
# Try reading a line from the input file
|
|
294
396
|
try:
|
|
295
397
|
with jobStore.read_file_stream(inJobStoreID) as f:
|
|
296
|
-
f = codecs.getreader(
|
|
398
|
+
f = codecs.getreader("utf-8")(f)
|
|
297
399
|
line = f.readline()
|
|
298
400
|
except:
|
|
299
|
-
logger.debug(
|
|
401
|
+
logger.debug(
|
|
402
|
+
"Something went wrong reading a line: %s",
|
|
403
|
+
traceback.format_exc(),
|
|
404
|
+
)
|
|
300
405
|
raise
|
|
301
406
|
|
|
302
407
|
if len(line.strip()) == 0:
|
|
@@ -307,7 +412,11 @@ class ToyService(Job.Service):
|
|
|
307
412
|
try:
|
|
308
413
|
inputInt = int(line)
|
|
309
414
|
except ValueError:
|
|
310
|
-
logger.debug(
|
|
415
|
+
logger.debug(
|
|
416
|
+
"Tried casting input line '%s' to integer but got error: %s",
|
|
417
|
+
line,
|
|
418
|
+
traceback.format_exc(),
|
|
419
|
+
)
|
|
311
420
|
continue
|
|
312
421
|
|
|
313
422
|
# Write out the resulting read integer and the message
|
|
@@ -318,28 +427,29 @@ class ToyService(Job.Service):
|
|
|
318
427
|
error.set()
|
|
319
428
|
raise
|
|
320
429
|
|
|
321
|
-
|
|
430
|
+
|
|
431
|
+
def serviceAccessor(job, communicationFiles, outFile, to_subtract):
|
|
322
432
|
"""
|
|
323
433
|
Writes a random integer iinto the inJobStoreFileID file, then tries 10 times reading
|
|
324
434
|
from outJobStoreFileID to get a pair of integers, the first equal to i the second written into the outputFile.
|
|
325
435
|
"""
|
|
326
436
|
inJobStoreFileID, outJobStoreFileID = communicationFiles
|
|
327
437
|
|
|
328
|
-
# Get a random integer
|
|
438
|
+
# Get a random integer to advertise ourselves
|
|
329
439
|
key = random.randint(1, sys.maxsize)
|
|
330
440
|
|
|
331
441
|
# Write the integer into the file
|
|
332
442
|
logger.debug("Writing key to inJobStoreFileID")
|
|
333
443
|
with job.fileStore.jobStore.update_file_stream(inJobStoreFileID) as fH:
|
|
334
|
-
fH.write(("%s\n" % key).encode(
|
|
444
|
+
fH.write(("%s\n" % key).encode("utf-8"))
|
|
335
445
|
|
|
336
446
|
logger.debug("Trying to read key and message from outJobStoreFileID")
|
|
337
|
-
for i in range(10):
|
|
338
|
-
time.sleep(0.2)
|
|
447
|
+
for i in range(10): # Try 10 times over
|
|
448
|
+
time.sleep(0.2) # Avoid thrashing
|
|
339
449
|
|
|
340
450
|
# Try reading an integer from the input file and writing out the message
|
|
341
451
|
with job.fileStore.jobStore.read_file_stream(outJobStoreFileID) as fH:
|
|
342
|
-
fH = codecs.getreader(
|
|
452
|
+
fH = codecs.getreader("utf-8")(fH)
|
|
343
453
|
line = fH.readline()
|
|
344
454
|
|
|
345
455
|
tokens = line.split()
|
|
@@ -349,12 +459,15 @@ def serviceAccessor(job, communicationFiles, outFile, randInt):
|
|
|
349
459
|
key2, message = tokens
|
|
350
460
|
|
|
351
461
|
if int(key2) == key:
|
|
352
|
-
logger.debug(
|
|
353
|
-
|
|
354
|
-
|
|
462
|
+
logger.debug(
|
|
463
|
+
f"Matched key's: {key}, writing message: {int(message) - to_subtract} with to_subtract: {to_subtract}"
|
|
464
|
+
)
|
|
465
|
+
with open(outFile, "a") as fH:
|
|
466
|
+
fH.write("%s\n" % (int(message) - to_subtract))
|
|
355
467
|
return
|
|
356
468
|
|
|
357
|
-
assert 0
|
|
469
|
+
assert 0 # Job failed to get info from the service
|
|
470
|
+
|
|
358
471
|
|
|
359
472
|
class ToySerializableService(Job.Service):
|
|
360
473
|
def __init__(self, messageInt, *args, **kwargs):
|
|
@@ -373,9 +486,10 @@ class ToySerializableService(Job.Service):
|
|
|
373
486
|
def check(self):
|
|
374
487
|
return True
|
|
375
488
|
|
|
489
|
+
|
|
376
490
|
def fnTest(strings, outputFile):
|
|
377
491
|
"""
|
|
378
492
|
Function concatenates the strings together and writes them to the output file
|
|
379
493
|
"""
|
|
380
|
-
with open(outputFile,
|
|
494
|
+
with open(outputFile, "w") as fH:
|
|
381
495
|
fH.write(" ".join(strings))
|