pybiolib 1.2.339__tar.gz → 1.2.340.dev1__tar.gz
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.
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/PKG-INFO +1 -1
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/utils/multinode.py +2 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/executors/docker_executor.py +51 -15
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/executors/types.py +7 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/job_worker.py +6 -6
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/webserver/worker_thread.py +34 -22
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/pyproject.toml +1 -1
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/LICENSE +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/PYPI_README.md +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_data_record/data_record.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/data_record/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/data_record/data_record.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/data_record/push_data.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/data_record/remote_storage_endpoint.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/file_utils.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/fuse_mount/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/fuse_mount/experiment_fuse_mount.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/http_client.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/lfs/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/lfs/cache.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/libs/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/libs/fusepy/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/push_application.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/runtime.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/types/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/types/app.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/types/data_record.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/types/experiment.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/types/file_node.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/types/resource.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/types/resource_version.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/types/typing.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/utils/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_runtime/runtime.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/api/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/api/client.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/app/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/app/app.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/app/search_apps.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_api_client/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_api_client/api_client.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_api_client/app_types.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_api_client/auth.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_api_client/biolib_app_api.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_api_client/biolib_job_api.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_api_client/common_types.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_api_client/job_types.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_api_client/lfs_types.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_api_client/user_state.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/base_bbf_package.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/file_in_container.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/module_input.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/module_output_v2.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/remote_endpoints.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/remote_stream_seeker.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/saved_job.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/stdout_and_stderr.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/system_exception.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/system_status_update.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/utils.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_docker_client/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_download_container.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_errors.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_logging.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/cli/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/cli/auth.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/cli/data_record.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/cli/download_container.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/cli/init.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/cli/lfs.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/cli/push.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/cli/run.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/cli/runtime.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/cli/start.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/.gitignore +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/cloud_utils/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/cloud_utils/cloud_utils.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/cache_state.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/cache_types.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/docker_image_cache.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/executors/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/executors/docker_types.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/executors/tars/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/job_legacy_input_wait_timeout_thread.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/job_max_runtime_timer_thread.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/job_storage.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/large_file_system.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/mappings.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/utilization_reporter_thread.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/utils.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/remote_host_proxy.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/socker_listener_thread.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/socket_sender_thread.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/utils.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/webserver/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/webserver/gunicorn_flask_application.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/webserver/webserver.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/webserver/webserver_types.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/webserver/webserver_utils.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/experiments/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/experiments/experiment.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/jobs/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/jobs/job.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/jobs/job_result.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/jobs/types.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/runtime/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/sdk/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/tables.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/templates/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/templates/example_app.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/typing_utils.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/user/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/user/sign_in.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/utils/__init__.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/utils/app_uri.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/utils/cache_state.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/utils/multipart_uploader.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/utils/seq_util.py +0 -0
- {pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/utils/zip/remote_zip.py +0 -0
@@ -84,6 +84,8 @@ def fasta_batch_records(records, work_per_batch_min, work_per_residue=1, verbose
|
|
84
84
|
n_seqs, n_res = batch_dict['records'], batch_dict['residues']
|
85
85
|
print(f'Batch {i+1}: {n_res} residues from {n_seqs} sequences')
|
86
86
|
|
87
|
+
# records = SeqUtil.parse_fasta(fasta_file)
|
88
|
+
|
87
89
|
batches = []
|
88
90
|
batch = []
|
89
91
|
current_work_units = 0
|
@@ -27,7 +27,7 @@ from biolib.compute_node import utils as compute_node_utils
|
|
27
27
|
from biolib.compute_node.cloud_utils import CloudUtils
|
28
28
|
from biolib.compute_node.job_worker.docker_image_cache import DockerImageCache
|
29
29
|
from biolib.compute_node.job_worker.executors.docker_types import DockerDiffKind
|
30
|
-
from biolib.compute_node.job_worker.executors.types import LocalExecutorOptions, StatusUpdate
|
30
|
+
from biolib.compute_node.job_worker.executors.types import LocalExecutorOptions, StatusUpdate, MetadataToSaveOutput
|
31
31
|
from biolib.compute_node.job_worker.mappings import Mappings, path_without_first_folder
|
32
32
|
from biolib.compute_node.job_worker.utilization_reporter_thread import UtilizationReporterThread
|
33
33
|
from biolib.compute_node.job_worker.utils import ComputeProcessException
|
@@ -61,9 +61,12 @@ class DockerExecutor:
|
|
61
61
|
os.makedirs(user_data_tar_dir, exist_ok=True)
|
62
62
|
|
63
63
|
self._docker_container: Optional[Container] = None
|
64
|
+
self._docker_api_client = BiolibDockerClient.get_docker_client().api
|
64
65
|
self._runtime_tar_path = f'{user_data_tar_dir}/runtime_{self._random_docker_id}.tar'
|
65
66
|
self._input_tar_path = f'{user_data_tar_dir}/input_{self._random_docker_id}.tar'
|
66
67
|
|
68
|
+
self._metadata_for_save_output_on_cancel: Optional[MetadataToSaveOutput] = None
|
69
|
+
|
67
70
|
if utils.IS_RUNNING_IN_CLOUD and not utils.BIOLIB_SECRETS_TMPFS_PATH:
|
68
71
|
error_message = 'Running in cloud but no TMPFS path has been set for secrets'
|
69
72
|
logger_no_user_data.error(error_message)
|
@@ -81,12 +84,12 @@ class DockerExecutor:
|
|
81
84
|
raise Exception('Docker container was None')
|
82
85
|
return self._docker_container
|
83
86
|
|
84
|
-
def execute_module(self
|
87
|
+
def execute_module(self) -> None:
|
85
88
|
try:
|
86
89
|
job_uuid = self._options['job']['public_id']
|
87
90
|
send_status_update = self._options['send_status_update']
|
88
91
|
logger_no_user_data.debug(f'Reading module input of {job_uuid}.')
|
89
|
-
with open(module_input_path, 'rb') as fp:
|
92
|
+
with open(self._options['module_input_path'], 'rb') as fp:
|
90
93
|
module_input_tmp = ModuleInput(fp.read())
|
91
94
|
logger_no_user_data.debug(f'Deserialing module input of {job_uuid}...')
|
92
95
|
module_input = module_input_tmp.deserialize()
|
@@ -100,7 +103,7 @@ class DockerExecutor:
|
|
100
103
|
|
101
104
|
logger_no_user_data.debug(f'Starting execution of {job_uuid}.')
|
102
105
|
try:
|
103
|
-
self._execute_helper(module_input
|
106
|
+
self._execute_helper(module_input)
|
104
107
|
except docker.errors.NotFound as docker_error:
|
105
108
|
raise DockerContainerNotFoundDuringExecutionException from docker_error
|
106
109
|
except Exception as exception:
|
@@ -161,7 +164,8 @@ class DockerExecutor:
|
|
161
164
|
may_contain_user_data=False,
|
162
165
|
)
|
163
166
|
|
164
|
-
|
167
|
+
|
168
|
+
def _execute_helper(self, module_input) -> None:
|
165
169
|
job_uuid = self._options['job']['public_id']
|
166
170
|
logger_no_user_data.debug(f'Initializing container for {job_uuid}.')
|
167
171
|
self._initialize_docker_container(module_input)
|
@@ -187,10 +191,9 @@ class DockerExecutor:
|
|
187
191
|
logger_no_user_data.debug(f'_map_and_copy_input_files_to_container for {job_uuid}.')
|
188
192
|
self._map_and_copy_input_files_to_container(module_input['files'], module_input['arguments'])
|
189
193
|
|
190
|
-
docker_api_client = BiolibDockerClient.get_docker_client().api
|
191
194
|
logger_no_user_data.debug(f'Attaching Docker container for {job_uuid}')
|
192
195
|
|
193
|
-
stdout_and_stderr_stream =
|
196
|
+
stdout_and_stderr_stream = self._docker_api_client.attach(
|
194
197
|
container=self._container.id,
|
195
198
|
stderr=True,
|
196
199
|
stdout=True,
|
@@ -211,6 +214,12 @@ class DockerExecutor:
|
|
211
214
|
logger.debug(f'Warning: Job "{job_uuid}" failed to start container. Hit error: {startup_error_string}')
|
212
215
|
# even though the container start failed we should still be able to call logs() and wait() on it, so we pass
|
213
216
|
|
217
|
+
self._metadata_for_save_output_on_cancel = MetadataToSaveOutput(
|
218
|
+
arguments=module_input['arguments'],
|
219
|
+
startup_error_string=startup_error_string,
|
220
|
+
pre_start_diff=pre_start_diff,
|
221
|
+
)
|
222
|
+
|
214
223
|
if self._options['job']['app_version'].get('stdout_render_type') != 'markdown':
|
215
224
|
logger_no_user_data.debug(f'Streaming stdout for {job_uuid}')
|
216
225
|
for stdout_and_stderr in stdout_and_stderr_stream:
|
@@ -220,7 +229,14 @@ class DockerExecutor:
|
|
220
229
|
self._send_stdout_and_stderr(stdout_and_stderr)
|
221
230
|
|
222
231
|
logger_no_user_data.debug(f'Waiting on docker for {job_uuid}')
|
223
|
-
|
232
|
+
try:
|
233
|
+
docker_result = self._docker_api_client.wait(self._container.id)
|
234
|
+
except docker.errors.NotFound as error:
|
235
|
+
if self._is_cleaning_up:
|
236
|
+
return
|
237
|
+
else:
|
238
|
+
raise error
|
239
|
+
|
224
240
|
logger_no_user_data.debug(f'Got result from docker for {job_uuid}')
|
225
241
|
exit_code = docker_result['StatusCode']
|
226
242
|
# 137 is the error code from linux OOM killer (Should catch 90% of OOM errors)
|
@@ -232,22 +248,26 @@ class DockerExecutor:
|
|
232
248
|
)
|
233
249
|
|
234
250
|
logger_no_user_data.debug(f'Docker container exited with code {exit_code} for {job_uuid}')
|
251
|
+
self._save_module_output_from_container(exit_code, self._metadata_for_save_output_on_cancel)
|
252
|
+
|
235
253
|
|
236
|
-
|
237
|
-
|
254
|
+
def _save_module_output_from_container(self, exit_code: int, metadata: MetadataToSaveOutput) -> None:
|
255
|
+
full_stdout = self._docker_api_client.logs(self._container.id, stdout=True, stderr=False)
|
256
|
+
full_stderr = self._docker_api_client.logs(self._container.id, stdout=False, stderr=True)
|
238
257
|
|
239
|
-
if startup_error_string:
|
240
|
-
full_stderr = full_stderr + startup_error_string.encode()
|
258
|
+
if metadata['startup_error_string']:
|
259
|
+
full_stderr = full_stderr + metadata['startup_error_string'].encode()
|
241
260
|
|
242
261
|
self._write_module_output_to_file(
|
243
|
-
arguments=
|
262
|
+
arguments=metadata['arguments'],
|
244
263
|
exit_code=exit_code,
|
245
|
-
module_output_path=module_output_path,
|
264
|
+
module_output_path=self._options['module_output_path'],
|
246
265
|
stderr=full_stderr,
|
247
266
|
stdout=full_stdout,
|
248
|
-
pre_start_diff=pre_start_diff,
|
267
|
+
pre_start_diff=metadata['pre_start_diff'],
|
249
268
|
)
|
250
269
|
|
270
|
+
|
251
271
|
def cleanup(self):
|
252
272
|
# Don't clean up if already in the process of doing so, or done doing so
|
253
273
|
if self._is_cleaning_up:
|
@@ -255,6 +275,22 @@ class DockerExecutor:
|
|
255
275
|
else:
|
256
276
|
self._is_cleaning_up = True
|
257
277
|
|
278
|
+
if self._metadata_for_save_output_on_cancel is not None:
|
279
|
+
try:
|
280
|
+
logger_no_user_data.debug('Attempting to save results')
|
281
|
+
self._docker_container.stop()
|
282
|
+
self._docker_container.reload()
|
283
|
+
logger_no_user_data.debug(f'Container state {self._docker_container.status}')
|
284
|
+
self._save_module_output_from_container(
|
285
|
+
exit_code=self._docker_container.attrs['State']['ExitCode'],
|
286
|
+
metadata=self._metadata_for_save_output_on_cancel
|
287
|
+
)
|
288
|
+
logger_no_user_data.debug('Saved results')
|
289
|
+
except BaseException as error:
|
290
|
+
logger_no_user_data.error(f'Failed to save results on cancel with error: {error}')
|
291
|
+
else:
|
292
|
+
logger_no_user_data.debug('Missing metadata, cannot save results')
|
293
|
+
|
258
294
|
tar_time = time.time()
|
259
295
|
for path_to_delete in [self._input_tar_path, self._runtime_tar_path]:
|
260
296
|
if os.path.exists(path_to_delete):
|
{pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/executors/types.py
RENAMED
@@ -34,9 +34,16 @@ class LocalExecutorOptions(TypedDict):
|
|
34
34
|
cloud_job: Optional[CloudJob]
|
35
35
|
large_file_systems: Dict[str, LargeFileSystem]
|
36
36
|
module: Module
|
37
|
+
module_input_path: str
|
38
|
+
module_output_path: str
|
37
39
|
remote_host_proxies: List[RemoteHostProxy]
|
38
40
|
root_job_id: str
|
39
41
|
runtime_zip_bytes: Optional[bytes] # TODO: replace this with a module_source_serialized
|
40
42
|
send_status_update: SendStatusUpdateType
|
41
43
|
send_system_exception: SendSystemExceptionType
|
42
44
|
send_stdout_and_stderr: SendStdoutAndStderrType
|
45
|
+
|
46
|
+
class MetadataToSaveOutput(TypedDict):
|
47
|
+
arguments: List[str]
|
48
|
+
startup_error_string: Optional[str]
|
49
|
+
pre_start_diff: List[Dict]
|
@@ -400,15 +400,15 @@ class JobWorker:
|
|
400
400
|
cloud_job=self._root_job_wrapper['cloud_job'],
|
401
401
|
large_file_systems=lfs_dict,
|
402
402
|
module=main_module,
|
403
|
+
module_input_path=module_input_path,
|
404
|
+
module_output_path=main_module_output_path,
|
403
405
|
remote_host_proxies=self._remote_host_proxies,
|
404
406
|
root_job_id=root_job_id,
|
405
407
|
runtime_zip_bytes=runtime_zip_bytes,
|
406
408
|
send_status_update=self._send_status_update,
|
407
409
|
send_system_exception=self.send_system_exception,
|
408
410
|
send_stdout_and_stderr=self.send_stdout_and_stderr,
|
409
|
-
)
|
410
|
-
module_input_path,
|
411
|
-
main_module_output_path,
|
411
|
+
)
|
412
412
|
)
|
413
413
|
|
414
414
|
if utils.IS_RUNNING_IN_CLOUD:
|
@@ -418,11 +418,11 @@ class JobWorker:
|
|
418
418
|
def _run_module(
|
419
419
|
self,
|
420
420
|
options: LocalExecutorOptions,
|
421
|
-
module_input_path: str,
|
422
|
-
module_output_path: str,
|
423
421
|
) -> None:
|
424
422
|
module = options['module']
|
425
423
|
job_id = options['job']['public_id']
|
424
|
+
module_output_path = options['module_output_path']
|
425
|
+
module_input_path = options['module_input_path']
|
426
426
|
logger_no_user_data.debug(f'Job "{job_id}" running module "{module["name"]}"...')
|
427
427
|
|
428
428
|
executor_instance: DockerExecutor
|
@@ -469,7 +469,7 @@ class JobWorker:
|
|
469
469
|
# Log memory and disk before pulling and executing module
|
470
470
|
log_disk_and_memory_usage_info()
|
471
471
|
|
472
|
-
executor_instance.execute_module(
|
472
|
+
executor_instance.execute_module()
|
473
473
|
|
474
474
|
def _connect_to_parent(self):
|
475
475
|
try:
|
@@ -7,6 +7,7 @@ import sys
|
|
7
7
|
import threading
|
8
8
|
import time
|
9
9
|
from queue import Queue
|
10
|
+
from typing import Optional
|
10
11
|
|
11
12
|
from biolib import api, utils
|
12
13
|
from biolib.biolib_binary_format import ModuleOutputV2, SystemException, SystemStatusUpdate
|
@@ -55,6 +56,26 @@ class WorkerThread(threading.Thread):
|
|
55
56
|
def _job_temporary_dir(self):
|
56
57
|
return self.compute_state['job_temporary_dir']
|
57
58
|
|
59
|
+
def _upload_module_output_and_get_exit_code(self) -> Optional[int]:
|
60
|
+
exit_code = None
|
61
|
+
try:
|
62
|
+
module_output_path = os.path.join(
|
63
|
+
self._job_temporary_dir,
|
64
|
+
JobStorage.module_output_file_name,
|
65
|
+
)
|
66
|
+
if os.path.exists(module_output_path):
|
67
|
+
module_output = ModuleOutputV2(buffer=LocalFileIndexableBuffer(filename=module_output_path))
|
68
|
+
exit_code = module_output.get_exit_code()
|
69
|
+
logger_no_user_data.debug(f'Got exit code: {exit_code}')
|
70
|
+
if utils.IS_RUNNING_IN_CLOUD:
|
71
|
+
JobStorage.upload_module_output(
|
72
|
+
job_temporary_dir=self._job_temporary_dir,
|
73
|
+
job_uuid=self._job_uuid,
|
74
|
+
)
|
75
|
+
except Exception as error:
|
76
|
+
logger_no_user_data.error(f'Could not upload module output or get exit code: {error}')
|
77
|
+
return exit_code
|
78
|
+
|
58
79
|
def run(self):
|
59
80
|
try:
|
60
81
|
while True:
|
@@ -77,25 +98,7 @@ class WorkerThread(threading.Thread):
|
|
77
98
|
|
78
99
|
# If 'Computation Finished'
|
79
100
|
if progress == 94:
|
80
|
-
|
81
|
-
try:
|
82
|
-
module_output_path = os.path.join(
|
83
|
-
self._job_temporary_dir,
|
84
|
-
JobStorage.module_output_file_name,
|
85
|
-
)
|
86
|
-
module_output = ModuleOutputV2(buffer=LocalFileIndexableBuffer(filename=module_output_path))
|
87
|
-
self.compute_state['exit_code'] = module_output.get_exit_code()
|
88
|
-
logger_no_user_data.debug(f"Got exit code: {self.compute_state['exit_code']}")
|
89
|
-
|
90
|
-
except Exception as error: # pylint: disable=broad-except
|
91
|
-
logger_no_user_data.error(f'Could not get exit_code from module output due to: {error}')
|
92
|
-
|
93
|
-
if utils.IS_RUNNING_IN_CLOUD:
|
94
|
-
JobStorage.upload_module_output(
|
95
|
-
job_temporary_dir=self._job_temporary_dir,
|
96
|
-
job_uuid=self._job_uuid,
|
97
|
-
)
|
98
|
-
|
101
|
+
self.compute_state['exit_code'] = self._upload_module_output_and_get_exit_code()
|
99
102
|
self._set_status_update(progress=95, log_message='Result Ready')
|
100
103
|
self.compute_state['is_completed'] = True
|
101
104
|
self.terminate()
|
@@ -174,13 +177,13 @@ class WorkerThread(threading.Thread):
|
|
174
177
|
|
175
178
|
def terminate(self) -> None:
|
176
179
|
cloud_job_uuid = self.compute_state['cloud_job_id']
|
177
|
-
exit_code = self.compute_state.get('exit_code')
|
178
180
|
system_exception_code = self.compute_state['status'].get('error_code')
|
179
|
-
|
181
|
+
|
182
|
+
if utils.IS_RUNNING_IN_CLOUD and system_exception_code != SystemExceptionCodes.CANCELLED_BY_USER.value:
|
180
183
|
CloudUtils.finish_cloud_job(
|
181
184
|
cloud_job_id=cloud_job_uuid,
|
182
185
|
system_exception_code=system_exception_code,
|
183
|
-
exit_code=exit_code,
|
186
|
+
exit_code=self.compute_state.get('exit_code', None),
|
184
187
|
)
|
185
188
|
|
186
189
|
deregistered_due_to_error = False
|
@@ -211,6 +214,15 @@ class WorkerThread(threading.Thread):
|
|
211
214
|
CloudUtils.deregister(error='job_cleanup_timed_out')
|
212
215
|
deregistered_due_to_error = True
|
213
216
|
|
217
|
+
elif system_exception_code == SystemExceptionCodes.CANCELLED_BY_USER.value:
|
218
|
+
self.compute_state['exit_code'] = self._upload_module_output_and_get_exit_code()
|
219
|
+
CloudUtils.finish_cloud_job(
|
220
|
+
cloud_job_id=cloud_job_uuid,
|
221
|
+
system_exception_code=system_exception_code,
|
222
|
+
exit_code=self.compute_state.get('exit_code', None),
|
223
|
+
)
|
224
|
+
|
225
|
+
|
214
226
|
# Delete result as error occurred
|
215
227
|
if system_exception_code and os.path.exists(self._job_temporary_dir):
|
216
228
|
shutil.rmtree(self._job_temporary_dir)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/data_record/remote_storage_endpoint.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/_internal/fuse_mount/experiment_fuse_mount.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/remote_stream_seeker.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/biolib_binary_format/system_status_update.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/docker_image_cache.py
RENAMED
File without changes
|
{pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/executors/__init__.py
RENAMED
File without changes
|
{pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/executors/docker_types.py
RENAMED
File without changes
|
{pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/executors/tars/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pybiolib-1.2.339 → pybiolib-1.2.340.dev1}/biolib/compute_node/job_worker/large_file_system.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|