pybiolib 0.2.951__py3-none-any.whl → 1.2.1890__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.
Files changed (262) hide show
  1. biolib/__init__.py +357 -11
  2. biolib/_data_record/data_record.py +380 -0
  3. biolib/_index/__init__.py +0 -0
  4. biolib/_index/index.py +55 -0
  5. biolib/_index/query_result.py +103 -0
  6. biolib/_internal/__init__.py +0 -0
  7. biolib/_internal/add_copilot_prompts.py +58 -0
  8. biolib/_internal/add_gui_files.py +81 -0
  9. biolib/_internal/data_record/__init__.py +1 -0
  10. biolib/_internal/data_record/data_record.py +85 -0
  11. biolib/_internal/data_record/push_data.py +116 -0
  12. biolib/_internal/data_record/remote_storage_endpoint.py +43 -0
  13. biolib/_internal/errors.py +5 -0
  14. biolib/_internal/file_utils.py +125 -0
  15. biolib/_internal/fuse_mount/__init__.py +1 -0
  16. biolib/_internal/fuse_mount/experiment_fuse_mount.py +209 -0
  17. biolib/_internal/http_client.py +159 -0
  18. biolib/_internal/lfs/__init__.py +1 -0
  19. biolib/_internal/lfs/cache.py +51 -0
  20. biolib/_internal/libs/__init__.py +1 -0
  21. biolib/_internal/libs/fusepy/__init__.py +1257 -0
  22. biolib/_internal/push_application.py +488 -0
  23. biolib/_internal/runtime.py +22 -0
  24. biolib/_internal/string_utils.py +13 -0
  25. biolib/_internal/templates/__init__.py +1 -0
  26. biolib/_internal/templates/copilot_template/.github/instructions/general-app-knowledge.instructions.md +10 -0
  27. biolib/_internal/templates/copilot_template/.github/instructions/style-general.instructions.md +20 -0
  28. biolib/_internal/templates/copilot_template/.github/instructions/style-python.instructions.md +16 -0
  29. biolib/_internal/templates/copilot_template/.github/instructions/style-react-ts.instructions.md +47 -0
  30. biolib/_internal/templates/copilot_template/.github/prompts/biolib_app_inputs.prompt.md +11 -0
  31. biolib/_internal/templates/copilot_template/.github/prompts/biolib_onboard_repo.prompt.md +19 -0
  32. biolib/_internal/templates/copilot_template/.github/prompts/biolib_run_apps.prompt.md +12 -0
  33. biolib/_internal/templates/dashboard_template/.biolib/config.yml +5 -0
  34. biolib/_internal/templates/github_workflow_template/.github/workflows/biolib.yml +21 -0
  35. biolib/_internal/templates/gitignore_template/.gitignore +10 -0
  36. biolib/_internal/templates/gui_template/.yarnrc.yml +1 -0
  37. biolib/_internal/templates/gui_template/App.tsx +53 -0
  38. biolib/_internal/templates/gui_template/Dockerfile +27 -0
  39. biolib/_internal/templates/gui_template/biolib-sdk.ts +82 -0
  40. biolib/_internal/templates/gui_template/dev-data/output.json +7 -0
  41. biolib/_internal/templates/gui_template/index.css +5 -0
  42. biolib/_internal/templates/gui_template/index.html +13 -0
  43. biolib/_internal/templates/gui_template/index.tsx +10 -0
  44. biolib/_internal/templates/gui_template/package.json +27 -0
  45. biolib/_internal/templates/gui_template/tsconfig.json +24 -0
  46. biolib/_internal/templates/gui_template/vite-plugin-dev-data.ts +50 -0
  47. biolib/_internal/templates/gui_template/vite.config.mts +10 -0
  48. biolib/_internal/templates/init_template/.biolib/config.yml +19 -0
  49. biolib/_internal/templates/init_template/Dockerfile +14 -0
  50. biolib/_internal/templates/init_template/requirements.txt +1 -0
  51. biolib/_internal/templates/init_template/run.py +12 -0
  52. biolib/_internal/templates/init_template/run.sh +4 -0
  53. biolib/_internal/templates/templates.py +25 -0
  54. biolib/_internal/tree_utils.py +106 -0
  55. biolib/_internal/utils/__init__.py +65 -0
  56. biolib/_internal/utils/auth.py +46 -0
  57. biolib/_internal/utils/job_url.py +33 -0
  58. biolib/_internal/utils/multinode.py +263 -0
  59. biolib/_runtime/runtime.py +157 -0
  60. biolib/_session/session.py +44 -0
  61. biolib/_shared/__init__.py +0 -0
  62. biolib/_shared/types/__init__.py +74 -0
  63. biolib/_shared/types/account.py +12 -0
  64. biolib/_shared/types/account_member.py +8 -0
  65. biolib/_shared/types/app.py +9 -0
  66. biolib/_shared/types/data_record.py +40 -0
  67. biolib/_shared/types/experiment.py +32 -0
  68. biolib/_shared/types/file_node.py +17 -0
  69. biolib/_shared/types/push.py +6 -0
  70. biolib/_shared/types/resource.py +37 -0
  71. biolib/_shared/types/resource_deploy_key.py +11 -0
  72. biolib/_shared/types/resource_permission.py +14 -0
  73. biolib/_shared/types/resource_version.py +19 -0
  74. biolib/_shared/types/result.py +14 -0
  75. biolib/_shared/types/typing.py +10 -0
  76. biolib/_shared/types/user.py +19 -0
  77. biolib/_shared/utils/__init__.py +7 -0
  78. biolib/_shared/utils/resource_uri.py +75 -0
  79. biolib/api/__init__.py +6 -0
  80. biolib/api/client.py +168 -0
  81. biolib/app/app.py +252 -49
  82. biolib/app/search_apps.py +45 -0
  83. biolib/biolib_api_client/api_client.py +126 -31
  84. biolib/biolib_api_client/app_types.py +24 -4
  85. biolib/biolib_api_client/auth.py +31 -8
  86. biolib/biolib_api_client/biolib_app_api.py +147 -52
  87. biolib/biolib_api_client/biolib_job_api.py +161 -141
  88. biolib/biolib_api_client/job_types.py +21 -5
  89. biolib/biolib_api_client/lfs_types.py +7 -23
  90. biolib/biolib_api_client/user_state.py +56 -0
  91. biolib/biolib_binary_format/__init__.py +1 -4
  92. biolib/biolib_binary_format/file_in_container.py +105 -0
  93. biolib/biolib_binary_format/module_input.py +24 -7
  94. biolib/biolib_binary_format/module_output_v2.py +149 -0
  95. biolib/biolib_binary_format/remote_endpoints.py +34 -0
  96. biolib/biolib_binary_format/remote_stream_seeker.py +59 -0
  97. biolib/biolib_binary_format/saved_job.py +3 -2
  98. biolib/biolib_binary_format/{attestation_document.py → stdout_and_stderr.py} +8 -8
  99. biolib/biolib_binary_format/system_status_update.py +3 -2
  100. biolib/biolib_binary_format/utils.py +175 -0
  101. biolib/biolib_docker_client/__init__.py +11 -2
  102. biolib/biolib_errors.py +36 -0
  103. biolib/biolib_logging.py +27 -10
  104. biolib/cli/__init__.py +38 -0
  105. biolib/cli/auth.py +46 -0
  106. biolib/cli/data_record.py +164 -0
  107. biolib/cli/index.py +32 -0
  108. biolib/cli/init.py +421 -0
  109. biolib/cli/lfs.py +101 -0
  110. biolib/cli/push.py +50 -0
  111. biolib/cli/run.py +63 -0
  112. biolib/cli/runtime.py +14 -0
  113. biolib/cli/sdk.py +16 -0
  114. biolib/cli/start.py +56 -0
  115. biolib/compute_node/cloud_utils/cloud_utils.py +110 -161
  116. biolib/compute_node/job_worker/cache_state.py +66 -88
  117. biolib/compute_node/job_worker/cache_types.py +1 -6
  118. biolib/compute_node/job_worker/docker_image_cache.py +112 -37
  119. biolib/compute_node/job_worker/executors/__init__.py +0 -3
  120. biolib/compute_node/job_worker/executors/docker_executor.py +532 -199
  121. biolib/compute_node/job_worker/executors/docker_types.py +9 -1
  122. biolib/compute_node/job_worker/executors/types.py +19 -9
  123. biolib/compute_node/job_worker/job_legacy_input_wait_timeout_thread.py +30 -0
  124. biolib/compute_node/job_worker/job_max_runtime_timer_thread.py +3 -5
  125. biolib/compute_node/job_worker/job_storage.py +108 -0
  126. biolib/compute_node/job_worker/job_worker.py +397 -212
  127. biolib/compute_node/job_worker/large_file_system.py +87 -38
  128. biolib/compute_node/job_worker/network_alloc.py +99 -0
  129. biolib/compute_node/job_worker/network_buffer.py +240 -0
  130. biolib/compute_node/job_worker/utilization_reporter_thread.py +197 -0
  131. biolib/compute_node/job_worker/utils.py +9 -24
  132. biolib/compute_node/remote_host_proxy.py +400 -98
  133. biolib/compute_node/utils.py +31 -9
  134. biolib/compute_node/webserver/compute_node_results_proxy.py +189 -0
  135. biolib/compute_node/webserver/proxy_utils.py +28 -0
  136. biolib/compute_node/webserver/webserver.py +130 -44
  137. biolib/compute_node/webserver/webserver_types.py +2 -6
  138. biolib/compute_node/webserver/webserver_utils.py +77 -12
  139. biolib/compute_node/webserver/worker_thread.py +183 -42
  140. biolib/experiments/__init__.py +0 -0
  141. biolib/experiments/experiment.py +356 -0
  142. biolib/jobs/__init__.py +1 -0
  143. biolib/jobs/job.py +741 -0
  144. biolib/jobs/job_result.py +185 -0
  145. biolib/jobs/types.py +50 -0
  146. biolib/py.typed +0 -0
  147. biolib/runtime/__init__.py +14 -0
  148. biolib/sdk/__init__.py +91 -0
  149. biolib/tables.py +34 -0
  150. biolib/typing_utils.py +2 -7
  151. biolib/user/__init__.py +1 -0
  152. biolib/user/sign_in.py +54 -0
  153. biolib/utils/__init__.py +162 -0
  154. biolib/utils/cache_state.py +94 -0
  155. biolib/utils/multipart_uploader.py +194 -0
  156. biolib/utils/seq_util.py +150 -0
  157. biolib/utils/zip/remote_zip.py +640 -0
  158. pybiolib-1.2.1890.dist-info/METADATA +41 -0
  159. pybiolib-1.2.1890.dist-info/RECORD +177 -0
  160. {pybiolib-0.2.951.dist-info → pybiolib-1.2.1890.dist-info}/WHEEL +1 -1
  161. pybiolib-1.2.1890.dist-info/entry_points.txt +2 -0
  162. README.md +0 -17
  163. biolib/app/app_result.py +0 -68
  164. biolib/app/utils.py +0 -62
  165. biolib/biolib-js/0-biolib.worker.js +0 -1
  166. biolib/biolib-js/1-biolib.worker.js +0 -1
  167. biolib/biolib-js/2-biolib.worker.js +0 -1
  168. biolib/biolib-js/3-biolib.worker.js +0 -1
  169. biolib/biolib-js/4-biolib.worker.js +0 -1
  170. biolib/biolib-js/5-biolib.worker.js +0 -1
  171. biolib/biolib-js/6-biolib.worker.js +0 -1
  172. biolib/biolib-js/index.html +0 -10
  173. biolib/biolib-js/main-biolib.js +0 -1
  174. biolib/biolib_api_client/biolib_account_api.py +0 -21
  175. biolib/biolib_api_client/biolib_large_file_system_api.py +0 -108
  176. biolib/biolib_binary_format/aes_encrypted_package.py +0 -42
  177. biolib/biolib_binary_format/module_output.py +0 -58
  178. biolib/biolib_binary_format/rsa_encrypted_aes_package.py +0 -57
  179. biolib/biolib_push.py +0 -114
  180. biolib/cli.py +0 -203
  181. biolib/cli_utils.py +0 -273
  182. biolib/compute_node/cloud_utils/enclave_parent_types.py +0 -7
  183. biolib/compute_node/enclave/__init__.py +0 -2
  184. biolib/compute_node/enclave/enclave_remote_hosts.py +0 -53
  185. biolib/compute_node/enclave/nitro_secure_module_utils.py +0 -64
  186. biolib/compute_node/job_worker/executors/base_executor.py +0 -18
  187. biolib/compute_node/job_worker/executors/pyppeteer_executor.py +0 -173
  188. biolib/compute_node/job_worker/executors/remote/__init__.py +0 -1
  189. biolib/compute_node/job_worker/executors/remote/nitro_enclave_utils.py +0 -81
  190. biolib/compute_node/job_worker/executors/remote/remote_executor.py +0 -51
  191. biolib/lfs.py +0 -196
  192. biolib/pyppeteer/.circleci/config.yml +0 -100
  193. biolib/pyppeteer/.coveragerc +0 -3
  194. biolib/pyppeteer/.gitignore +0 -89
  195. biolib/pyppeteer/.pre-commit-config.yaml +0 -28
  196. biolib/pyppeteer/CHANGES.md +0 -253
  197. biolib/pyppeteer/CONTRIBUTING.md +0 -26
  198. biolib/pyppeteer/LICENSE +0 -12
  199. biolib/pyppeteer/README.md +0 -137
  200. biolib/pyppeteer/docs/Makefile +0 -177
  201. biolib/pyppeteer/docs/_static/custom.css +0 -28
  202. biolib/pyppeteer/docs/_templates/layout.html +0 -10
  203. biolib/pyppeteer/docs/changes.md +0 -1
  204. biolib/pyppeteer/docs/conf.py +0 -299
  205. biolib/pyppeteer/docs/index.md +0 -21
  206. biolib/pyppeteer/docs/make.bat +0 -242
  207. biolib/pyppeteer/docs/reference.md +0 -211
  208. biolib/pyppeteer/docs/server.py +0 -60
  209. biolib/pyppeteer/poetry.lock +0 -1699
  210. biolib/pyppeteer/pyppeteer/__init__.py +0 -135
  211. biolib/pyppeteer/pyppeteer/accessibility.py +0 -286
  212. biolib/pyppeteer/pyppeteer/browser.py +0 -401
  213. biolib/pyppeteer/pyppeteer/browser_fetcher.py +0 -194
  214. biolib/pyppeteer/pyppeteer/command.py +0 -22
  215. biolib/pyppeteer/pyppeteer/connection/__init__.py +0 -242
  216. biolib/pyppeteer/pyppeteer/connection/cdpsession.py +0 -101
  217. biolib/pyppeteer/pyppeteer/coverage.py +0 -346
  218. biolib/pyppeteer/pyppeteer/device_descriptors.py +0 -787
  219. biolib/pyppeteer/pyppeteer/dialog.py +0 -79
  220. biolib/pyppeteer/pyppeteer/domworld.py +0 -597
  221. biolib/pyppeteer/pyppeteer/emulation_manager.py +0 -53
  222. biolib/pyppeteer/pyppeteer/errors.py +0 -48
  223. biolib/pyppeteer/pyppeteer/events.py +0 -63
  224. biolib/pyppeteer/pyppeteer/execution_context.py +0 -156
  225. biolib/pyppeteer/pyppeteer/frame/__init__.py +0 -299
  226. biolib/pyppeteer/pyppeteer/frame/frame_manager.py +0 -306
  227. biolib/pyppeteer/pyppeteer/helpers.py +0 -245
  228. biolib/pyppeteer/pyppeteer/input.py +0 -371
  229. biolib/pyppeteer/pyppeteer/jshandle.py +0 -598
  230. biolib/pyppeteer/pyppeteer/launcher.py +0 -683
  231. biolib/pyppeteer/pyppeteer/lifecycle_watcher.py +0 -169
  232. biolib/pyppeteer/pyppeteer/models/__init__.py +0 -103
  233. biolib/pyppeteer/pyppeteer/models/_protocol.py +0 -12460
  234. biolib/pyppeteer/pyppeteer/multimap.py +0 -82
  235. biolib/pyppeteer/pyppeteer/network_manager.py +0 -678
  236. biolib/pyppeteer/pyppeteer/options.py +0 -8
  237. biolib/pyppeteer/pyppeteer/page.py +0 -1728
  238. biolib/pyppeteer/pyppeteer/pipe_transport.py +0 -59
  239. biolib/pyppeteer/pyppeteer/target.py +0 -147
  240. biolib/pyppeteer/pyppeteer/task_queue.py +0 -24
  241. biolib/pyppeteer/pyppeteer/timeout_settings.py +0 -36
  242. biolib/pyppeteer/pyppeteer/tracing.py +0 -93
  243. biolib/pyppeteer/pyppeteer/us_keyboard_layout.py +0 -305
  244. biolib/pyppeteer/pyppeteer/util.py +0 -18
  245. biolib/pyppeteer/pyppeteer/websocket_transport.py +0 -47
  246. biolib/pyppeteer/pyppeteer/worker.py +0 -101
  247. biolib/pyppeteer/pyproject.toml +0 -97
  248. biolib/pyppeteer/spell.txt +0 -137
  249. biolib/pyppeteer/tox.ini +0 -72
  250. biolib/pyppeteer/utils/generate_protocol_types.py +0 -603
  251. biolib/start_cli.py +0 -7
  252. biolib/utils.py +0 -47
  253. biolib/validators/validate_app_version.py +0 -183
  254. biolib/validators/validate_argument.py +0 -134
  255. biolib/validators/validate_module.py +0 -323
  256. biolib/validators/validate_zip_file.py +0 -40
  257. biolib/validators/validator_utils.py +0 -103
  258. pybiolib-0.2.951.dist-info/LICENSE +0 -21
  259. pybiolib-0.2.951.dist-info/METADATA +0 -61
  260. pybiolib-0.2.951.dist-info/RECORD +0 -153
  261. pybiolib-0.2.951.dist-info/entry_points.txt +0 -3
  262. /LICENSE → /pybiolib-1.2.1890.dist-info/licenses/LICENSE +0 -0
@@ -4,51 +4,90 @@ import subprocess
4
4
  from docker.errors import ImageNotFound, APIError # type: ignore
5
5
 
6
6
  from biolib import utils
7
+ from biolib.typing_utils import TypedDict
7
8
  from biolib.biolib_docker_client import BiolibDockerClient
8
- from biolib.compute_node.cloud_utils import CloudUtils
9
+ from biolib.biolib_errors import BioLibError
10
+ from biolib.biolib_logging import logger_no_user_data
9
11
  from biolib.compute_node.job_worker.cache_state import DockerImageCacheState, DockerCacheStateError
10
- from biolib.compute_node.job_worker.cache_types import DockerImageInfo, DockerImageCacheStateDict, DockerAuthConfig
12
+ from biolib.compute_node.job_worker.cache_types import DockerImageInfo, DockerImageCacheStateDict, UuidStr
13
+
14
+
15
+ class DiskUsage(TypedDict):
16
+ image_storage_available_in_bytes: int
17
+ max_image_capacity_in_bytes: int
18
+ used_in_bytes: int
11
19
 
12
20
 
13
21
  class DockerImageCache:
14
22
  def __init__(self):
15
- config = CloudUtils.get_webserver_config()
16
- self._max_cache_size = config['max_docker_image_cache_size_bytes'] # pylint: disable=unsubscriptable-object
23
+ if not utils.IS_RUNNING_IN_CLOUD:
24
+ raise BioLibError('Using DockerImageCache outside Cloud is not supported')
25
+
17
26
  self._docker_client = BiolibDockerClient().get_docker_client()
18
27
  self._docker_data_dir = self._docker_client.info()['DockerRootDir']
19
28
 
20
- @property
21
- def _current_cache_size_on_disk(self):
22
- disk_usage_command = ["/bin/bash", "-c", f"du -sb {self._docker_data_dir} | cut -f1"]
23
- if not utils.BIOLIB_IS_RUNNING_IN_ENCLAVE:
24
- # Need to use sudo outside of enclave
25
- disk_usage_command.insert(0, "sudo")
26
-
27
- du_output = subprocess.run(
29
+ def _get_current_disk_usage_stats(self) -> DiskUsage:
30
+ disk_usage_command = ['df', '--block-size=1', self._docker_data_dir]
31
+ logger_no_user_data.debug(f'Running {disk_usage_command}...')
32
+ df_output = subprocess.run(
28
33
  disk_usage_command,
29
34
  capture_output=True,
30
- check=True
31
- ).stdout
32
- return int(du_output.decode().strip())
35
+ check=True,
36
+ timeout=3,
37
+ ).stdout.decode()
38
+ logger_no_user_data.debug(df_output)
39
+ df_output_lines = [s.split() for s in df_output.splitlines()]
40
+
41
+ # Expect the filesystem to be row 1
42
+ disk = df_output_lines[1]
43
+ # Expect column 1 to be total disk size and column 2 to be disk space used
44
+ total_size_in_bytes = int(disk[1])
45
+ used_in_bytes = int(disk[2])
46
+
47
+ # Allow 80% to be used for images
48
+ max_image_capacity_in_bytes = total_size_in_bytes * 80 // 100
49
+ available_for_images_in_bytes = max(0, max_image_capacity_in_bytes - used_in_bytes)
50
+
51
+ disk_usage = DiskUsage(
52
+ image_storage_available_in_bytes=available_for_images_in_bytes,
53
+ max_image_capacity_in_bytes=max_image_capacity_in_bytes,
54
+ used_in_bytes=used_in_bytes,
55
+ )
56
+ logger_no_user_data.debug(f'Disk usage for Docker: {disk_usage}')
57
+ return disk_usage
33
58
 
34
59
  def _clear_space_for_image(self, estimated_image_size_bytes: int, cache_state: DockerImageCacheStateDict):
35
- while not self._has_space_to_pull_image(estimated_image_size_bytes, cache_state):
36
- self._remove_least_recently_used_image(cache_state)
37
-
38
- def get(self, image_uri: str, estimated_image_size_bytes: int, pull_auth_config: DockerAuthConfig):
60
+ for _ in range(100):
61
+ if not self._has_space_to_pull_image(estimated_image_size_bytes, cache_state):
62
+ self._remove_least_recently_used_image(cache_state)
63
+ else:
64
+ return
65
+
66
+ raise DockerCacheStateError('Failed to free space for Docker image')
67
+
68
+ def get(
69
+ self,
70
+ image_uri: str,
71
+ estimated_image_size_bytes: int,
72
+ job_id: str,
73
+ ) -> None:
39
74
  try:
40
75
  with DockerImageCacheState() as cache_state:
76
+ if image_uri not in cache_state:
77
+ raise ImageNotFound('Image not found in cache')
78
+
41
79
  self._docker_client.images.get(image_uri)
42
80
  cache_state[image_uri]['last_used_at'] = DockerImageCacheState.get_timestamp_now()
81
+ cache_state[image_uri]['active_jobs'].append(job_id)
43
82
 
44
83
  except ImageNotFound:
45
- if estimated_image_size_bytes > self._max_cache_size:
46
- CloudUtils.log(
47
- f"Image {image_uri} with size: {estimated_image_size_bytes} is bigger than the max cache size",
48
- logging.ERROR
84
+ disk_stats = self._get_current_disk_usage_stats()
85
+ if estimated_image_size_bytes > disk_stats['max_image_capacity_in_bytes']:
86
+ logger_no_user_data.error(
87
+ f'Image {image_uri} with size: {estimated_image_size_bytes} is bigger than the max cache size'
49
88
  )
50
89
  raise DockerCacheStateError( # pylint: disable=raise-missing-from
51
- "Image is bigger than the max cache size"
90
+ 'Image is bigger than the max cache size'
52
91
  )
53
92
 
54
93
  with DockerImageCacheState() as cache_state:
@@ -59,26 +98,56 @@ class DockerImageCache:
59
98
  last_used_at=DockerImageCacheState.get_timestamp_now(),
60
99
  uri=image_uri,
61
100
  state='pulling',
62
- estimated_image_size_bytes=estimated_image_size_bytes
101
+ estimated_image_size_bytes=estimated_image_size_bytes,
102
+ active_jobs=[job_id]
63
103
  )
64
104
 
65
- CloudUtils.log(f'Image {image_uri} not found in cache. Pulling...', logging.DEBUG)
66
- self._docker_client.images.pull(image_uri, auth_config=pull_auth_config)
105
+ logger_no_user_data.debug(f'Image {image_uri} not found in cache. Pulling...')
106
+ try:
107
+ self._docker_client.images.pull(image_uri)
108
+ except Exception as error:
109
+ logger_no_user_data.error(f'Could not pull image due to {error}')
110
+
111
+ # Remove image from cache_state
112
+ with DockerImageCacheState() as cache_state:
113
+ if image_uri in cache_state:
114
+ cache_state.pop(image_uri)
115
+
116
+ raise error
117
+
67
118
  with DockerImageCacheState() as cache_state:
68
119
  cache_state[image_uri]['state'] = 'ready'
69
120
 
121
+ @staticmethod
122
+ def detach_job(image_uri: str, job_id: UuidStr) -> None:
123
+ try:
124
+ with DockerImageCacheState() as cache_state:
125
+ if image_uri in cache_state and job_id in cache_state[image_uri]['active_jobs']:
126
+ cache_state[image_uri]['active_jobs'].remove(job_id)
127
+
128
+ except Exception as error: # pylint: disable=broad-except
129
+ logging.error('Could not remove job from image cache')
130
+ logging.error(error)
131
+
70
132
  def _remove_least_recently_used_image(self, cache_state: DockerImageCacheStateDict) -> None:
71
133
  cached_images = [image for image in cache_state.values() if image['state'] == 'ready']
72
134
  images_sorted_by_least_recently_used = sorted(cached_images, key=lambda image: image['last_used_at'])
73
135
 
74
136
  for image in images_sorted_by_least_recently_used:
75
- CloudUtils.log(f"Removing image: {image['uri']}", logging.DEBUG)
137
+ logger_no_user_data.debug(f"Removing image: {image['uri']}")
138
+
139
+ # Only remove images that has no active jobs
140
+ if image['active_jobs']:
141
+ logger_no_user_data.debug(
142
+ f"Skipping removal of image {image['uri']} as it has the active jobs {image['active_jobs']}"
143
+ )
144
+ continue
145
+
76
146
  try:
77
147
  self._docker_client.api.remove_image(image=image['uri'])
78
148
  except APIError as error:
79
- CloudUtils.log(
80
- f"Could not remove image due to {error}... Skipping removal of this image.",
81
- logging.ERROR
149
+ logger_no_user_data.error(
150
+ f'Could not remove image due to {error}... Skipping removal of this image.'
82
151
  )
83
152
  continue # Image is in use or cannot be removed at this time
84
153
 
@@ -86,11 +155,17 @@ class DockerImageCache:
86
155
  break
87
156
 
88
157
  def _has_space_to_pull_image(self, estimated_image_size_bytes: int, cache_state: DockerImageCacheStateDict) -> bool:
89
- size_of_images_being_pulled = sum([image['estimated_image_size_bytes'] for image in cache_state.values()
90
- if image['state'] == 'pulling'])
91
- current_cache_size = self._current_cache_size_on_disk + size_of_images_being_pulled
92
-
93
- cache_space_remaining = self._max_cache_size - current_cache_size
94
- CloudUtils.log(f"Cache space remaining: {cache_space_remaining}", logging.DEBUG)
158
+ logger_no_user_data.debug('Calculating cache metrics...')
159
+ size_of_images_being_pulled = sum(
160
+ [image['estimated_image_size_bytes'] for image in cache_state.values() if image['state'] == 'pulling']
161
+ )
162
+ disk_stats = self._get_current_disk_usage_stats()
163
+ cache_space_remaining = disk_stats['image_storage_available_in_bytes'] - size_of_images_being_pulled
164
+
165
+ logger_no_user_data.debug(
166
+ f'Needed current image: {estimated_image_size_bytes}. '
167
+ f'Cache remaining: {cache_space_remaining}. '
168
+ f'Total pulling: {size_of_images_being_pulled}. '
169
+ )
95
170
 
96
171
  return bool(cache_space_remaining > estimated_image_size_bytes)
@@ -1,5 +1,2 @@
1
- from biolib.compute_node.job_worker.executors.pyppeteer_executor import PyppeteerExecutor
2
1
  from biolib.compute_node.job_worker.executors.docker_executor import DockerExecutor
3
- from biolib.compute_node.job_worker.executors.remote import RemoteExecutor
4
-
5
2
  from biolib.compute_node.job_worker.executors.types import *