pybiolib 1.2.334.dev1__py3-none-any.whl → 1.2.339__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.
- biolib/_internal/utils/multinode.py +0 -2
 - biolib/compute_node/job_worker/executors/docker_executor.py +15 -51
 - biolib/compute_node/job_worker/executors/types.py +0 -7
 - biolib/compute_node/job_worker/job_worker.py +6 -6
 - biolib/compute_node/webserver/worker_thread.py +21 -27
 - {pybiolib-1.2.334.dev1.dist-info → pybiolib-1.2.339.dist-info}/METADATA +1 -1
 - {pybiolib-1.2.334.dev1.dist-info → pybiolib-1.2.339.dist-info}/RECORD +10 -10
 - {pybiolib-1.2.334.dev1.dist-info → pybiolib-1.2.339.dist-info}/LICENSE +0 -0
 - {pybiolib-1.2.334.dev1.dist-info → pybiolib-1.2.339.dist-info}/WHEEL +0 -0
 - {pybiolib-1.2.334.dev1.dist-info → pybiolib-1.2.339.dist-info}/entry_points.txt +0 -0
 
| 
         @@ -84,8 +84,6 @@ 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 
     | 
    
         
            -
             
     | 
| 
       89 
87 
     | 
    
         
             
                batches = []
         
     | 
| 
       90 
88 
     | 
    
         
             
                batch = []
         
     | 
| 
       91 
89 
     | 
    
         
             
                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
         
     | 
| 
       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,12 +61,9 @@ 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
         
     | 
| 
       65 
64 
     | 
    
         
             
                    self._runtime_tar_path = f'{user_data_tar_dir}/runtime_{self._random_docker_id}.tar'
         
     | 
| 
       66 
65 
     | 
    
         
             
                    self._input_tar_path = f'{user_data_tar_dir}/input_{self._random_docker_id}.tar'
         
     | 
| 
       67 
66 
     | 
    
         | 
| 
       68 
     | 
    
         
            -
                    self._metadata_for_save_output_on_cancel: Optional[MetadataToSaveOutput] = None
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
67 
     | 
    
         
             
                    if utils.IS_RUNNING_IN_CLOUD and not utils.BIOLIB_SECRETS_TMPFS_PATH:
         
     | 
| 
       71 
68 
     | 
    
         
             
                        error_message = 'Running in cloud but no TMPFS path has been set for secrets'
         
     | 
| 
       72 
69 
     | 
    
         
             
                        logger_no_user_data.error(error_message)
         
     | 
| 
         @@ -84,12 +81,12 @@ class DockerExecutor: 
     | 
|
| 
       84 
81 
     | 
    
         
             
                        raise Exception('Docker container was None')
         
     | 
| 
       85 
82 
     | 
    
         
             
                    return self._docker_container
         
     | 
| 
       86 
83 
     | 
    
         | 
| 
       87 
     | 
    
         
            -
                def execute_module(self) -> None:
         
     | 
| 
      
 84 
     | 
    
         
            +
                def execute_module(self, module_input_path: str, module_output_path: str) -> None:
         
     | 
| 
       88 
85 
     | 
    
         
             
                    try:
         
     | 
| 
       89 
86 
     | 
    
         
             
                        job_uuid = self._options['job']['public_id']
         
     | 
| 
       90 
87 
     | 
    
         
             
                        send_status_update = self._options['send_status_update']
         
     | 
| 
       91 
88 
     | 
    
         
             
                        logger_no_user_data.debug(f'Reading module input of {job_uuid}.')
         
     | 
| 
       92 
     | 
    
         
            -
                        with open( 
     | 
| 
      
 89 
     | 
    
         
            +
                        with open(module_input_path, 'rb') as fp:
         
     | 
| 
       93 
90 
     | 
    
         
             
                            module_input_tmp = ModuleInput(fp.read())
         
     | 
| 
       94 
91 
     | 
    
         
             
                            logger_no_user_data.debug(f'Deserialing module input of {job_uuid}...')
         
     | 
| 
       95 
92 
     | 
    
         
             
                            module_input = module_input_tmp.deserialize()
         
     | 
| 
         @@ -103,7 +100,7 @@ class DockerExecutor: 
     | 
|
| 
       103 
100 
     | 
    
         | 
| 
       104 
101 
     | 
    
         
             
                        logger_no_user_data.debug(f'Starting execution of {job_uuid}.')
         
     | 
| 
       105 
102 
     | 
    
         
             
                        try:
         
     | 
| 
       106 
     | 
    
         
            -
                            self._execute_helper(module_input)
         
     | 
| 
      
 103 
     | 
    
         
            +
                            self._execute_helper(module_input, module_output_path)
         
     | 
| 
       107 
104 
     | 
    
         
             
                        except docker.errors.NotFound as docker_error:
         
     | 
| 
       108 
105 
     | 
    
         
             
                            raise DockerContainerNotFoundDuringExecutionException from docker_error
         
     | 
| 
       109 
106 
     | 
    
         
             
                        except Exception as exception:
         
     | 
| 
         @@ -164,8 +161,7 @@ class DockerExecutor: 
     | 
|
| 
       164 
161 
     | 
    
         
             
                        may_contain_user_data=False,
         
     | 
| 
       165 
162 
     | 
    
         
             
                    )
         
     | 
| 
       166 
163 
     | 
    
         | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
       168 
     | 
    
         
            -
                def _execute_helper(self, module_input) -> None:
         
     | 
| 
      
 164 
     | 
    
         
            +
                def _execute_helper(self, module_input, module_output_path: str) -> None:
         
     | 
| 
       169 
165 
     | 
    
         
             
                    job_uuid = self._options['job']['public_id']
         
     | 
| 
       170 
166 
     | 
    
         
             
                    logger_no_user_data.debug(f'Initializing container for {job_uuid}.')
         
     | 
| 
       171 
167 
     | 
    
         
             
                    self._initialize_docker_container(module_input)
         
     | 
| 
         @@ -191,9 +187,10 @@ class DockerExecutor: 
     | 
|
| 
       191 
187 
     | 
    
         
             
                    logger_no_user_data.debug(f'_map_and_copy_input_files_to_container for {job_uuid}.')
         
     | 
| 
       192 
188 
     | 
    
         
             
                    self._map_and_copy_input_files_to_container(module_input['files'], module_input['arguments'])
         
     | 
| 
       193 
189 
     | 
    
         | 
| 
      
 190 
     | 
    
         
            +
                    docker_api_client = BiolibDockerClient.get_docker_client().api
         
     | 
| 
       194 
191 
     | 
    
         
             
                    logger_no_user_data.debug(f'Attaching Docker container for {job_uuid}')
         
     | 
| 
       195 
192 
     | 
    
         | 
| 
       196 
     | 
    
         
            -
                    stdout_and_stderr_stream =  
     | 
| 
      
 193 
     | 
    
         
            +
                    stdout_and_stderr_stream = docker_api_client.attach(
         
     | 
| 
       197 
194 
     | 
    
         
             
                        container=self._container.id,
         
     | 
| 
       198 
195 
     | 
    
         
             
                        stderr=True,
         
     | 
| 
       199 
196 
     | 
    
         
             
                        stdout=True,
         
     | 
| 
         @@ -214,12 +211,6 @@ class DockerExecutor: 
     | 
|
| 
       214 
211 
     | 
    
         
             
                        logger.debug(f'Warning: Job "{job_uuid}" failed to start container. Hit error: {startup_error_string}')
         
     | 
| 
       215 
212 
     | 
    
         
             
                        # even though the container start failed we should still be able to call logs() and wait() on it, so we pass
         
     | 
| 
       216 
213 
     | 
    
         | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
       223 
214 
     | 
    
         
             
                    if self._options['job']['app_version'].get('stdout_render_type') != 'markdown':
         
     | 
| 
       224 
215 
     | 
    
         
             
                        logger_no_user_data.debug(f'Streaming stdout for {job_uuid}')
         
     | 
| 
       225 
216 
     | 
    
         
             
                        for stdout_and_stderr in stdout_and_stderr_stream:
         
     | 
| 
         @@ -229,14 +220,7 @@ class DockerExecutor: 
     | 
|
| 
       229 
220 
     | 
    
         
             
                            self._send_stdout_and_stderr(stdout_and_stderr)
         
     | 
| 
       230 
221 
     | 
    
         | 
| 
       231 
222 
     | 
    
         
             
                    logger_no_user_data.debug(f'Waiting on docker for {job_uuid}')
         
     | 
| 
       232 
     | 
    
         
            -
                     
     | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
      
 223 
     | 
    
         
            +
                    docker_result = docker_api_client.wait(self._container.id)
         
     | 
| 
       240 
224 
     | 
    
         
             
                    logger_no_user_data.debug(f'Got result from docker for {job_uuid}')
         
     | 
| 
       241 
225 
     | 
    
         
             
                    exit_code = docker_result['StatusCode']
         
     | 
| 
       242 
226 
     | 
    
         
             
                    # 137 is the error code from linux OOM killer (Should catch 90% of OOM errors)
         
     | 
| 
         @@ -248,26 +232,22 @@ class DockerExecutor: 
     | 
|
| 
       248 
232 
     | 
    
         
             
                        )
         
     | 
| 
       249 
233 
     | 
    
         | 
| 
       250 
234 
     | 
    
         
             
                    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 
     | 
    
         
            -
             
     | 
| 
       253 
235 
     | 
    
         | 
| 
       254 
     | 
    
         
            -
             
     | 
| 
       255 
     | 
    
         
            -
                     
     | 
| 
       256 
     | 
    
         
            -
                    full_stderr = self._docker_api_client.logs(self._container.id, stdout=False, stderr=True)
         
     | 
| 
      
 236 
     | 
    
         
            +
                    full_stdout = docker_api_client.logs(self._container.id, stdout=True, stderr=False)
         
     | 
| 
      
 237 
     | 
    
         
            +
                    full_stderr = docker_api_client.logs(self._container.id, stdout=False, stderr=True)
         
     | 
| 
       257 
238 
     | 
    
         | 
| 
       258 
     | 
    
         
            -
                    if  
     | 
| 
       259 
     | 
    
         
            -
                        full_stderr = full_stderr +  
     | 
| 
      
 239 
     | 
    
         
            +
                    if startup_error_string:
         
     | 
| 
      
 240 
     | 
    
         
            +
                        full_stderr = full_stderr + startup_error_string.encode()
         
     | 
| 
       260 
241 
     | 
    
         | 
| 
       261 
242 
     | 
    
         
             
                    self._write_module_output_to_file(
         
     | 
| 
       262 
     | 
    
         
            -
                        arguments= 
     | 
| 
      
 243 
     | 
    
         
            +
                        arguments=module_input['arguments'],
         
     | 
| 
       263 
244 
     | 
    
         
             
                        exit_code=exit_code,
         
     | 
| 
       264 
     | 
    
         
            -
                        module_output_path= 
     | 
| 
      
 245 
     | 
    
         
            +
                        module_output_path=module_output_path,
         
     | 
| 
       265 
246 
     | 
    
         
             
                        stderr=full_stderr,
         
     | 
| 
       266 
247 
     | 
    
         
             
                        stdout=full_stdout,
         
     | 
| 
       267 
     | 
    
         
            -
                        pre_start_diff= 
     | 
| 
      
 248 
     | 
    
         
            +
                        pre_start_diff=pre_start_diff,
         
     | 
| 
       268 
249 
     | 
    
         
             
                    )
         
     | 
| 
       269 
250 
     | 
    
         | 
| 
       270 
     | 
    
         
            -
             
     | 
| 
       271 
251 
     | 
    
         
             
                def cleanup(self):
         
     | 
| 
       272 
252 
     | 
    
         
             
                    # Don't clean up if already in the process of doing so, or done doing so
         
     | 
| 
       273 
253 
     | 
    
         
             
                    if self._is_cleaning_up:
         
     | 
| 
         @@ -275,22 +255,6 @@ class DockerExecutor: 
     | 
|
| 
       275 
255 
     | 
    
         
             
                    else:
         
     | 
| 
       276 
256 
     | 
    
         
             
                        self._is_cleaning_up = True
         
     | 
| 
       277 
257 
     | 
    
         | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
       294 
258 
     | 
    
         
             
                    tar_time = time.time()
         
     | 
| 
       295 
259 
     | 
    
         
             
                    for path_to_delete in [self._input_tar_path, self._runtime_tar_path]:
         
     | 
| 
       296 
260 
     | 
    
         
             
                        if os.path.exists(path_to_delete):
         
     | 
| 
         @@ -34,16 +34,9 @@ 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
         
     | 
| 
       39 
37 
     | 
    
         
             
                remote_host_proxies: List[RemoteHostProxy]
         
     | 
| 
       40 
38 
     | 
    
         
             
                root_job_id: str
         
     | 
| 
       41 
39 
     | 
    
         
             
                runtime_zip_bytes: Optional[bytes]  # TODO: replace this with a module_source_serialized
         
     | 
| 
       42 
40 
     | 
    
         
             
                send_status_update: SendStatusUpdateType
         
     | 
| 
       43 
41 
     | 
    
         
             
                send_system_exception: SendSystemExceptionType
         
     | 
| 
       44 
42 
     | 
    
         
             
                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,
         
     | 
| 
       405 
403 
     | 
    
         
             
                            remote_host_proxies=self._remote_host_proxies,
         
     | 
| 
       406 
404 
     | 
    
         
             
                            root_job_id=root_job_id,
         
     | 
| 
       407 
405 
     | 
    
         
             
                            runtime_zip_bytes=runtime_zip_bytes,
         
     | 
| 
       408 
406 
     | 
    
         
             
                            send_status_update=self._send_status_update,
         
     | 
| 
       409 
407 
     | 
    
         
             
                            send_system_exception=self.send_system_exception,
         
     | 
| 
       410 
408 
     | 
    
         
             
                            send_stdout_and_stderr=self.send_stdout_and_stderr,
         
     | 
| 
       411 
     | 
    
         
            -
                        )
         
     | 
| 
      
 409 
     | 
    
         
            +
                        ),
         
     | 
| 
      
 410 
     | 
    
         
            +
                        module_input_path,
         
     | 
| 
      
 411 
     | 
    
         
            +
                        main_module_output_path,
         
     | 
| 
       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,
         
     | 
| 
       421 
423 
     | 
    
         
             
                ) -> None:
         
     | 
| 
       422 
424 
     | 
    
         
             
                    module = options['module']
         
     | 
| 
       423 
425 
     | 
    
         
             
                    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(module_input_path, module_output_path)
         
     | 
| 
       473 
473 
     | 
    
         | 
| 
       474 
474 
     | 
    
         
             
                def _connect_to_parent(self):
         
     | 
| 
       475 
475 
     | 
    
         
             
                    try:
         
     | 
| 
         @@ -7,7 +7,6 @@ import sys 
     | 
|
| 
       7 
7 
     | 
    
         
             
            import threading
         
     | 
| 
       8 
8 
     | 
    
         
             
            import time
         
     | 
| 
       9 
9 
     | 
    
         
             
            from queue import Queue
         
     | 
| 
       10 
     | 
    
         
            -
            from typing import Optional
         
     | 
| 
       11 
10 
     | 
    
         | 
| 
       12 
11 
     | 
    
         
             
            from biolib import api, utils
         
     | 
| 
       13 
12 
     | 
    
         
             
            from biolib.biolib_binary_format import ModuleOutputV2, SystemException, SystemStatusUpdate
         
     | 
| 
         @@ -56,26 +55,6 @@ class WorkerThread(threading.Thread): 
     | 
|
| 
       56 
55 
     | 
    
         
             
                def _job_temporary_dir(self):
         
     | 
| 
       57 
56 
     | 
    
         
             
                    return self.compute_state['job_temporary_dir']
         
     | 
| 
       58 
57 
     | 
    
         | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
       79 
58 
     | 
    
         
             
                def run(self):
         
     | 
| 
       80 
59 
     | 
    
         
             
                    try:
         
     | 
| 
       81 
60 
     | 
    
         
             
                        while True:
         
     | 
| 
         @@ -98,7 +77,25 @@ class WorkerThread(threading.Thread): 
     | 
|
| 
       98 
77 
     | 
    
         | 
| 
       99 
78 
     | 
    
         
             
                                # If 'Computation Finished'
         
     | 
| 
       100 
79 
     | 
    
         
             
                                if progress == 94:
         
     | 
| 
       101 
     | 
    
         
            -
                                     
     | 
| 
      
 80 
     | 
    
         
            +
                                    # Get Job exit code
         
     | 
| 
      
 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 
     | 
    
         
            +
             
     | 
| 
       102 
99 
     | 
    
         
             
                                    self._set_status_update(progress=95, log_message='Result Ready')
         
     | 
| 
       103 
100 
     | 
    
         
             
                                    self.compute_state['is_completed'] = True
         
     | 
| 
       104 
101 
     | 
    
         
             
                                    self.terminate()
         
     | 
| 
         @@ -177,16 +174,13 @@ class WorkerThread(threading.Thread): 
     | 
|
| 
       177 
174 
     | 
    
         | 
| 
       178 
175 
     | 
    
         
             
                def terminate(self) -> None:
         
     | 
| 
       179 
176 
     | 
    
         
             
                    cloud_job_uuid = self.compute_state['cloud_job_id']
         
     | 
| 
      
 177 
     | 
    
         
            +
                    exit_code = self.compute_state.get('exit_code')
         
     | 
| 
       180 
178 
     | 
    
         
             
                    system_exception_code = self.compute_state['status'].get('error_code')
         
     | 
| 
       181 
     | 
    
         
            -
             
     | 
| 
       182 
179 
     | 
    
         
             
                    if utils.IS_RUNNING_IN_CLOUD:
         
     | 
| 
       183 
     | 
    
         
            -
                        if system_exception_code == SystemExceptionCodes.CANCELLED_BY_USER.value:
         
     | 
| 
       184 
     | 
    
         
            -
                            self.compute_state['exit_code'] = self._upload_module_output_and_get_exit_code()
         
     | 
| 
       185 
     | 
    
         
            -
             
     | 
| 
       186 
180 
     | 
    
         
             
                        CloudUtils.finish_cloud_job(
         
     | 
| 
       187 
181 
     | 
    
         
             
                            cloud_job_id=cloud_job_uuid,
         
     | 
| 
       188 
182 
     | 
    
         
             
                            system_exception_code=system_exception_code,
         
     | 
| 
       189 
     | 
    
         
            -
                            exit_code= 
     | 
| 
      
 183 
     | 
    
         
            +
                            exit_code=exit_code,
         
     | 
| 
       190 
184 
     | 
    
         
             
                        )
         
     | 
| 
       191 
185 
     | 
    
         | 
| 
       192 
186 
     | 
    
         
             
                    deregistered_due_to_error = False
         
     | 
| 
         @@ -24,7 +24,7 @@ biolib/_internal/types/resource.py,sha256=G-vPkZoe4Um6FPxsQZtRzAlbSW5sDW4NFkbjn2 
     | 
|
| 
       24 
24 
     | 
    
         
             
            biolib/_internal/types/resource_version.py,sha256=sLxViYXloDDUhTDFgjegiQCj097OM1Ih1-uqlC_4ULA,174
         
     | 
| 
       25 
25 
     | 
    
         
             
            biolib/_internal/types/typing.py,sha256=D4EKKEe7kDx0K6lJi-H_XLtk-8w6nu2fdqn9bvzI-Xo,288
         
     | 
| 
       26 
26 
     | 
    
         
             
            biolib/_internal/utils/__init__.py,sha256=p5vsIFyu-zYqBgdSMfwW9NC_jk7rXvvCbV4Bzd3As7c,630
         
     | 
| 
       27 
     | 
    
         
            -
            biolib/_internal/utils/multinode.py,sha256 
     | 
| 
      
 27 
     | 
    
         
            +
            biolib/_internal/utils/multinode.py,sha256=-J3PEAK3NaOwCn--5T7vWHkA3yu5w9QhmuhkQcH-2wY,8229
         
     | 
| 
       28 
28 
     | 
    
         
             
            biolib/_runtime/runtime.py,sha256=bZQ0m39R9jOBVAtlyvzDnOobKueOAQUCwMUZjDQnO7E,4439
         
     | 
| 
       29 
29 
     | 
    
         
             
            biolib/api/__init__.py,sha256=mQ4u8FijqyLzjYMezMUUbbBGNB3iFmkNdjXnWPZ7Jlw,138
         
     | 
| 
       30 
30 
     | 
    
         
             
            biolib/api/client.py,sha256=_kmwaGI_-u7kOeWVCYmo-pD2K1imwEv9n2gNZRb5F-I,3790
         
     | 
| 
         @@ -76,14 +76,14 @@ biolib/compute_node/job_worker/cache_state.py,sha256=MwjSRzcJJ_4jybqvBL4xdgnDYSI 
     | 
|
| 
       76 
76 
     | 
    
         
             
            biolib/compute_node/job_worker/cache_types.py,sha256=ajpLy8i09QeQS9dEqTn3T6NVNMY_YsHQkSD5nvIHccQ,818
         
     | 
| 
       77 
77 
     | 
    
         
             
            biolib/compute_node/job_worker/docker_image_cache.py,sha256=ansHIkJIq_EMW1nZNlW-RRLVVeKWTbzNICYaOHpKiRE,7460
         
     | 
| 
       78 
78 
     | 
    
         
             
            biolib/compute_node/job_worker/executors/__init__.py,sha256=bW6t1qi3PZTlHM4quaTLa8EI4ALTCk83cqcVJfJfJfE,145
         
     | 
| 
       79 
     | 
    
         
            -
            biolib/compute_node/job_worker/executors/docker_executor.py,sha256= 
     | 
| 
      
 79 
     | 
    
         
            +
            biolib/compute_node/job_worker/executors/docker_executor.py,sha256=J-wv7FTb_HJnfRdIByiOdtj18Fw5nYvVm-n0D1mrqwA,29377
         
     | 
| 
       80 
80 
     | 
    
         
             
            biolib/compute_node/job_worker/executors/docker_types.py,sha256=VhsU1DKtJjx_BbCkVmiPZPH4ROiL1ygW1Y_s1Kbpa2o,216
         
     | 
| 
       81 
81 
     | 
    
         
             
            biolib/compute_node/job_worker/executors/tars/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       82 
     | 
    
         
            -
            biolib/compute_node/job_worker/executors/types.py,sha256= 
     | 
| 
      
 82 
     | 
    
         
            +
            biolib/compute_node/job_worker/executors/types.py,sha256=yP5gG39hr-DLnw9bOE--VHi-1arDbIYiGuV1rlTbbHI,1466
         
     | 
| 
       83 
83 
     | 
    
         
             
            biolib/compute_node/job_worker/job_legacy_input_wait_timeout_thread.py,sha256=_cvEiZbOwfkv6fYmfrvdi_FVviIEYr_dSClQcOQaUWM,1198
         
     | 
| 
       84 
84 
     | 
    
         
             
            biolib/compute_node/job_worker/job_max_runtime_timer_thread.py,sha256=K_xgz7IhiIjpLlXRk8sqaMyLoApcidJkgu29sJX0gb8,1174
         
     | 
| 
       85 
85 
     | 
    
         
             
            biolib/compute_node/job_worker/job_storage.py,sha256=lScHI3ubcHKagSEW243tgbIWXUfbWDHDjEOPMvXxJE8,4603
         
     | 
| 
       86 
     | 
    
         
            -
            biolib/compute_node/job_worker/job_worker.py,sha256= 
     | 
| 
      
 86 
     | 
    
         
            +
            biolib/compute_node/job_worker/job_worker.py,sha256=fuWoYJo9HOqLmWl8yeCXh0mhT4ebbkrWac-BVb58khs,28842
         
     | 
| 
       87 
87 
     | 
    
         
             
            biolib/compute_node/job_worker/large_file_system.py,sha256=XXqRlVtYhs-Ji9zQGIk5KQPXFO_Q5jJH0nnlw4GkeMY,10461
         
     | 
| 
       88 
88 
     | 
    
         
             
            biolib/compute_node/job_worker/mappings.py,sha256=Z48Kg4nbcOvsT2-9o3RRikBkqflgO4XeaWxTGz-CNvI,2499
         
     | 
| 
       89 
89 
     | 
    
         
             
            biolib/compute_node/job_worker/utilization_reporter_thread.py,sha256=7tm5Yk9coqJ9VbEdnO86tSXI0iM0omwIyKENxdxiVXk,8575
         
     | 
| 
         @@ -97,7 +97,7 @@ biolib/compute_node/webserver/gunicorn_flask_application.py,sha256=jPfR_YvNBekLU 
     | 
|
| 
       97 
97 
     | 
    
         
             
            biolib/compute_node/webserver/webserver.py,sha256=o4kOAStsqThUtKlnRE-U5TP0JIYntuySDjU7PH310xg,6620
         
     | 
| 
       98 
98 
     | 
    
         
             
            biolib/compute_node/webserver/webserver_types.py,sha256=2t8EaFKESnves3BA_NBdnS2yAdo1qwamCFHiSt888nE,380
         
     | 
| 
       99 
99 
     | 
    
         
             
            biolib/compute_node/webserver/webserver_utils.py,sha256=XWvwYPbWNR3qS0FYbLLp-MDDfVk0QdaAmg3xPrT0H2s,4234
         
     | 
| 
       100 
     | 
    
         
            -
            biolib/compute_node/webserver/worker_thread.py,sha256= 
     | 
| 
      
 100 
     | 
    
         
            +
            biolib/compute_node/webserver/worker_thread.py,sha256=GRRBUqXdMKvbjyLQhYlqGIbFKeU2iiEXIe5IXi9wgdg,11806
         
     | 
| 
       101 
101 
     | 
    
         
             
            biolib/experiments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       102 
102 
     | 
    
         
             
            biolib/experiments/experiment.py,sha256=m7FB7hot8CMOVrNyWGPB6FTkWQJwI0ytpIvtPxfoPME,7684
         
     | 
| 
       103 
103 
     | 
    
         
             
            biolib/jobs/__init__.py,sha256=aIb2H2DHjQbM2Bs-dysFijhwFcL58Blp0Co0gimED3w,32
         
     | 
| 
         @@ -118,8 +118,8 @@ biolib/utils/cache_state.py,sha256=u256F37QSRIVwqKlbnCyzAX4EMI-kl6Dwu6qwj-Qmag,3 
     | 
|
| 
       118 
118 
     | 
    
         
             
            biolib/utils/multipart_uploader.py,sha256=XvGP1I8tQuKhAH-QugPRoEsCi9qvbRk-DVBs5PNwwJo,8452
         
     | 
| 
       119 
119 
     | 
    
         
             
            biolib/utils/seq_util.py,sha256=Ozk0blGtPur_D9MwShD02r_mphyQmgZkx-lOHOwnlIM,6730
         
     | 
| 
       120 
120 
     | 
    
         
             
            biolib/utils/zip/remote_zip.py,sha256=0wErYlxir5921agfFeV1xVjf29l9VNgGQvNlWOlj2Yc,23232
         
     | 
| 
       121 
     | 
    
         
            -
            pybiolib-1.2. 
     | 
| 
       122 
     | 
    
         
            -
            pybiolib-1.2. 
     | 
| 
       123 
     | 
    
         
            -
            pybiolib-1.2. 
     | 
| 
       124 
     | 
    
         
            -
            pybiolib-1.2. 
     | 
| 
       125 
     | 
    
         
            -
            pybiolib-1.2. 
     | 
| 
      
 121 
     | 
    
         
            +
            pybiolib-1.2.339.dist-info/LICENSE,sha256=F2h7gf8i0agDIeWoBPXDMYScvQOz02pAWkKhTGOHaaw,1067
         
     | 
| 
      
 122 
     | 
    
         
            +
            pybiolib-1.2.339.dist-info/METADATA,sha256=7w5znJtkMyO9KQ_CD0PdX2Hz1pBuTjnEOeSnfaOMrsk,1570
         
     | 
| 
      
 123 
     | 
    
         
            +
            pybiolib-1.2.339.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
         
     | 
| 
      
 124 
     | 
    
         
            +
            pybiolib-1.2.339.dist-info/entry_points.txt,sha256=p6DyaP_2kctxegTX23WBznnrDi4mz6gx04O5uKtRDXg,42
         
     | 
| 
      
 125 
     | 
    
         
            +
            pybiolib-1.2.339.dist-info/RECORD,,
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     |