fractal-server 2.14.0a24__tar.gz → 2.14.0a25__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.
Files changed (215) hide show
  1. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/PKG-INFO +1 -1
  2. fractal_server-2.14.0a25/fractal_server/__init__.py +1 -0
  3. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/v2/history.py +1 -1
  4. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/history.py +4 -2
  5. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/base_runner.py +20 -36
  6. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/local/get_local_config.py +5 -0
  7. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/local/runner.py +4 -47
  8. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_common/_slurm_config.py +4 -0
  9. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +26 -63
  10. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_common/get_slurm_config.py +38 -1
  11. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/task_files.py +29 -0
  12. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/db_tools.py +0 -15
  13. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/runner.py +4 -8
  14. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/runner_functions.py +97 -40
  15. fractal_server-2.14.0a25/fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +39 -0
  16. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/pyproject.toml +2 -2
  17. fractal_server-2.14.0a24/fractal_server/__init__.py +0 -1
  18. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/LICENSE +0 -0
  19. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/README.md +0 -0
  20. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/__main__.py +0 -0
  21. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/alembic.ini +0 -0
  22. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/__init__.py +0 -0
  23. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/db/__init__.py +0 -0
  24. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/history/__init__.py +0 -0
  25. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/__init__.py +0 -0
  26. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/linkusergroup.py +0 -0
  27. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/linkuserproject.py +0 -0
  28. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/security.py +0 -0
  29. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/user_settings.py +0 -0
  30. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/v2/__init__.py +0 -0
  31. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/v2/accounting.py +0 -0
  32. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/v2/dataset.py +0 -0
  33. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/v2/job.py +0 -0
  34. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/v2/project.py +0 -0
  35. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/v2/task.py +0 -0
  36. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/v2/task_group.py +0 -0
  37. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/v2/workflow.py +0 -0
  38. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/models/v2/workflowtask.py +0 -0
  39. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/__init__.py +0 -0
  40. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/admin/__init__.py +0 -0
  41. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
  42. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
  43. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
  44. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/admin/v2/job.py +0 -0
  45. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/admin/v2/project.py +0 -0
  46. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/admin/v2/task.py +0 -0
  47. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
  48. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +0 -0
  49. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/__init__.py +0 -0
  50. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  51. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
  52. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/_aux_functions_history.py +0 -0
  53. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
  54. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
  55. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/dataset.py +0 -0
  56. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/images.py +0 -0
  57. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/job.py +0 -0
  58. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/project.py +0 -0
  59. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/status_legacy.py +0 -0
  60. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/submit.py +0 -0
  61. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/task.py +0 -0
  62. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/task_collection.py +0 -0
  63. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
  64. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/task_group.py +0 -0
  65. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +0 -0
  66. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/verify_image_types.py +0 -0
  67. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  68. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
  69. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
  70. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/auth/__init__.py +0 -0
  71. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
  72. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/auth/current_user.py +0 -0
  73. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/auth/group.py +0 -0
  74. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/auth/login.py +0 -0
  75. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/auth/oauth.py +0 -0
  76. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/auth/register.py +0 -0
  77. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/auth/router.py +0 -0
  78. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/auth/users.py +0 -0
  79. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/aux/__init__.py +0 -0
  80. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/aux/_job.py +0 -0
  81. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/aux/_runner.py +0 -0
  82. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/aux/validate_user_settings.py +0 -0
  83. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/routes/pagination.py +0 -0
  84. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/__init__.py +0 -0
  85. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/components.py +0 -0
  86. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/compress_folder.py +0 -0
  87. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/exceptions.py +0 -0
  88. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/__init__.py +0 -0
  89. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/local/__init__.py +0 -0
  90. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_common/__init__.py +0 -0
  91. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_common/_batching.py +0 -0
  92. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_common/_job_states.py +0 -0
  93. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_common/remote.py +0 -0
  94. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +0 -0
  95. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_common/utils_executors.py +0 -0
  96. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_ssh/__init__.py +0 -0
  97. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_ssh/runner.py +0 -0
  98. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_sudo/__init__.py +0 -0
  99. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
  100. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/executors/slurm_sudo/runner.py +0 -0
  101. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/extract_archive.py +0 -0
  102. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/filenames.py +0 -0
  103. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/run_subprocess.py +0 -0
  104. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
  105. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/shutdown.py +0 -0
  106. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/__init__.py +0 -0
  107. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/_local.py +0 -0
  108. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/_slurm_ssh.py +0 -0
  109. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/_slurm_sudo.py +0 -0
  110. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
  111. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
  112. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/runner_functions_low_level.py +0 -0
  113. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/submit_workflow.py +0 -0
  114. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/v2/task_interface.py +0 -0
  115. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/runner/versions.py +0 -0
  116. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/__init__.py +0 -0
  117. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/_filter_validators.py +0 -0
  118. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/_validators.py +0 -0
  119. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/user.py +0 -0
  120. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/user_group.py +0 -0
  121. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/user_settings.py +0 -0
  122. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/__init__.py +0 -0
  123. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/accounting.py +0 -0
  124. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/dataset.py +0 -0
  125. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/dumps.py +0 -0
  126. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/history.py +0 -0
  127. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/job.py +0 -0
  128. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/manifest.py +0 -0
  129. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/project.py +0 -0
  130. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
  131. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/task.py +0 -0
  132. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/task_collection.py +0 -0
  133. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/task_group.py +0 -0
  134. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/workflow.py +0 -0
  135. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
  136. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/security/__init__.py +0 -0
  137. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/security/signup_email.py +0 -0
  138. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/app/user_settings.py +0 -0
  139. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/config.py +0 -0
  140. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/data_migrations/README.md +0 -0
  141. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/data_migrations/tools.py +0 -0
  142. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/gunicorn_fractal.py +0 -0
  143. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/images/__init__.py +0 -0
  144. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/images/models.py +0 -0
  145. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/images/tools.py +0 -0
  146. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/logger.py +0 -0
  147. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/main.py +0 -0
  148. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/env.py +0 -0
  149. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/naming_convention.py +0 -0
  150. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
  151. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
  152. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
  153. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
  154. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
  155. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
  156. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  157. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  158. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
  159. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  160. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  161. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  162. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  163. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  164. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
  165. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  166. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
  167. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  168. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  169. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
  170. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
  171. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  172. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  173. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
  174. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
  175. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
  176. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  177. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
  178. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
  179. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  180. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
  181. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  182. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  183. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
  184. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/py.typed +0 -0
  185. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/ssh/__init__.py +0 -0
  186. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/ssh/_fabric.py +0 -0
  187. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/string_tools.py +0 -0
  188. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/syringe.py +0 -0
  189. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/__init__.py +0 -0
  190. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/utils.py +0 -0
  191. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/__init__.py +0 -0
  192. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/local/__init__.py +0 -0
  193. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/local/_utils.py +0 -0
  194. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/local/collect.py +0 -0
  195. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/local/deactivate.py +0 -0
  196. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/local/reactivate.py +0 -0
  197. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
  198. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
  199. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/ssh/collect.py +0 -0
  200. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
  201. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
  202. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
  203. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
  204. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
  205. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
  206. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
  207. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
  208. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/utils_background.py +0 -0
  209. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/utils_database.py +0 -0
  210. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/utils_package_names.py +0 -0
  211. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
  212. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/tasks/v2/utils_templates.py +0 -0
  213. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/urls.py +0 -0
  214. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/utils.py +0 -0
  215. {fractal_server-2.14.0a24 → fractal_server-2.14.0a25}/fractal_server/zip_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fractal-server
3
- Version: 2.14.0a24
3
+ Version: 2.14.0a25
4
4
  Summary: Backend component of the Fractal analytics platform
5
5
  License: BSD-3-Clause
6
6
  Author: Tommaso Comparin
@@ -0,0 +1 @@
1
+ __VERSION__ = "2.14.0a25"
@@ -50,7 +50,7 @@ class HistoryUnit(SQLModel, table=True):
50
50
  ondelete="CASCADE",
51
51
  )
52
52
 
53
- logfile: Optional[str]
53
+ logfile: str
54
54
  status: str
55
55
  zarr_urls: list[str] = Field(
56
56
  sa_column=Column(ARRAY(String)),
@@ -249,8 +249,10 @@ async def get_history_run_units(
249
249
  page_size = pagination.page_size or total_count
250
250
 
251
251
  # Query `HistoryUnit`s
252
- stmt = select(HistoryUnit).where(
253
- HistoryUnit.history_run_id == history_run_id
252
+ stmt = (
253
+ select(HistoryUnit)
254
+ .where(HistoryUnit.history_run_id == history_run_id)
255
+ .order_by(HistoryUnit.id)
254
256
  )
255
257
  if unit_status:
256
258
  stmt = stmt.where(HistoryUnit.status == unit_status)
@@ -4,7 +4,6 @@ from fractal_server.app.runner.task_files import TaskFiles
4
4
  from fractal_server.app.schemas.v2.task import TaskTypeType
5
5
  from fractal_server.logger import set_logger
6
6
 
7
-
8
7
  TASK_TYPES_SUBMIT: list[TaskTypeType] = [
9
8
  "compound",
10
9
  "converter_compound",
@@ -103,29 +102,44 @@ class BaseRunner(object):
103
102
 
104
103
  def validate_multisubmit_parameters(
105
104
  self,
106
- list_parameters: list[dict[str, Any]],
105
+ *,
107
106
  task_type: TaskTypeType,
107
+ list_parameters: list[dict[str, Any]],
108
108
  list_task_files: list[TaskFiles],
109
+ history_unit_ids: list[int],
109
110
  ) -> None:
110
111
  """
111
112
  Validate parameters for `multisubmit` method
112
113
 
113
114
  Args:
114
- list_parameters: List of parameters dictionaries.
115
115
  task_type: Task type.
116
+ list_parameters: List of parameters dictionaries.
117
+ list_task_files:
118
+ history_unit_ids:
116
119
  """
117
120
  if task_type not in TASK_TYPES_MULTISUBMIT:
118
121
  raise ValueError(f"Invalid {task_type=} for `multisubmit`.")
119
122
 
123
+ if not isinstance(list_parameters, list):
124
+ raise ValueError("`parameters` must be a list.")
125
+
126
+ if len(list_parameters) != len(list_task_files):
127
+ raise ValueError(
128
+ f"{len(list_task_files)=} differs from "
129
+ f"{len(list_parameters)=}."
130
+ )
131
+ if len(history_unit_ids) != len(list_parameters):
132
+ raise ValueError(
133
+ f"{len(history_unit_ids)=} differs from "
134
+ f"{len(list_parameters)=}."
135
+ )
136
+
120
137
  subfolders = set(
121
138
  task_file.wftask_subfolder_local for task_file in list_task_files
122
139
  )
123
140
  if len(subfolders) != 1:
124
141
  raise ValueError(f"More than one subfolders: {subfolders}.")
125
142
 
126
- if not isinstance(list_parameters, list):
127
- raise ValueError("`parameters` must be a list.")
128
-
129
143
  for single_kwargs in list_parameters:
130
144
  if not isinstance(single_kwargs, dict):
131
145
  raise ValueError("kwargs itemt must be a dictionary.")
@@ -137,33 +151,3 @@ class BaseRunner(object):
137
151
  zarr_urls = [kwargs["zarr_url"] for kwargs in list_parameters]
138
152
  if len(zarr_urls) != len(set(zarr_urls)):
139
153
  raise ValueError("Non-unique zarr_urls")
140
-
141
- def validate_multisubmit_history_unit_ids(
142
- self,
143
- *,
144
- history_unit_ids: list[int],
145
- task_type: TaskTypeType,
146
- list_parameters: list[dict[str, Any]],
147
- ) -> None:
148
- """
149
- Run preliminary check for multisubmit inputs.
150
-
151
- Args:
152
- history_unit_ids:
153
- task_type:
154
- list_parameters:
155
- """
156
- if task_type in ["compound", "converter_compound"]:
157
- if len(history_unit_ids) != 1:
158
- raise NotImplementedError(
159
- "We are breaking the assumption that compound/multisubmit "
160
- "is associated to a single HistoryUnit. This is not "
161
- "supported."
162
- )
163
- elif task_type == "parallel" and len(history_unit_ids) != len(
164
- list_parameters
165
- ):
166
- raise ValueError(
167
- f"{len(history_unit_ids)=} differs from "
168
- f"{len(list_parameters)=}."
169
- )
@@ -47,11 +47,16 @@ class LocalBackendConfig(BaseModel):
47
47
  model_config = ConfigDict(extra="forbid")
48
48
  parallel_tasks_per_job: Optional[int] = None
49
49
 
50
+ @property
51
+ def batch_size(self) -> int:
52
+ return self.parallel_tasks_per_job or 1
53
+
50
54
 
51
55
  def get_local_backend_config(
52
56
  wftask: WorkflowTaskV2,
53
57
  which_type: Literal["non_parallel", "parallel"],
54
58
  config_path: Optional[Path] = None,
59
+ tot_tasks: int = 1,
55
60
  ) -> LocalBackendConfig:
56
61
  """
57
62
  Prepare a `LocalBackendConfig` configuration object
@@ -8,12 +8,7 @@ from .get_local_config import LocalBackendConfig
8
8
  from fractal_server.app.db import get_sync_db
9
9
  from fractal_server.app.runner.exceptions import TaskExecutionError
10
10
  from fractal_server.app.runner.executors.base_runner import BaseRunner
11
- from fractal_server.app.runner.task_files import MULTISUBMIT_PREFIX
12
- from fractal_server.app.runner.task_files import SUBMIT_PREFIX
13
11
  from fractal_server.app.runner.task_files import TaskFiles
14
- from fractal_server.app.runner.v2.db_tools import (
15
- update_logfile_of_history_unit,
16
- )
17
12
  from fractal_server.app.runner.v2.db_tools import update_status_of_history_unit
18
13
  from fractal_server.app.schemas.v2 import HistoryUnitStatus
19
14
  from fractal_server.logger import set_logger
@@ -68,13 +63,6 @@ class LocalRunner(BaseRunner):
68
63
  workdir_local = task_files.wftask_subfolder_local
69
64
  workdir_local.mkdir()
70
65
 
71
- # Add prefix to task_files object
72
- task_files.prefix = SUBMIT_PREFIX
73
- update_logfile_of_history_unit(
74
- history_unit_id=history_unit_id,
75
- logfile=task_files.log_file_local,
76
- )
77
-
78
66
  # SUBMISSION PHASE
79
67
  future = self.executor.submit(
80
68
  func,
@@ -111,29 +99,18 @@ class LocalRunner(BaseRunner):
111
99
  list_task_files: list[TaskFiles],
112
100
  task_type: Literal["parallel", "compound", "converter_compound"],
113
101
  config: LocalBackendConfig,
114
- ):
102
+ ) -> tuple[dict[int, Any], dict[int, BaseException]]:
115
103
  """
116
- Note:
117
-
118
- 1. The number of sruns and futures is equal to `len(list_parameters)`.
119
- 2. The number of `HistoryUnit`s is equal to `len(history_unit_ids)`.
120
- 3. For compound tasks, these two numbers are not the same.
121
-
122
- For this reason, we defer database updates to the caller function,
123
- when we are in one of the "compound" cases
124
-
104
+ Note: `list_parameters`, `list_task_files` and `history_unit_ids`
105
+ have the same size. For parallel tasks, this is also the number of
106
+ input images, while for compound tasks these can differ.
125
107
  """
126
108
 
127
109
  self.validate_multisubmit_parameters(
128
110
  list_parameters=list_parameters,
129
111
  task_type=task_type,
130
112
  list_task_files=list_task_files,
131
- )
132
-
133
- self.validate_multisubmit_history_unit_ids(
134
113
  history_unit_ids=history_unit_ids,
135
- task_type=task_type,
136
- list_parameters=list_parameters,
137
114
  )
138
115
 
139
116
  logger.debug(f"[multisubmit] START, {len(list_parameters)=}")
@@ -159,9 +136,6 @@ class LocalRunner(BaseRunner):
159
136
  active_futures: dict[int, Future] = {}
160
137
  for ind_within_chunk, kwargs in enumerate(list_parameters_chunk):
161
138
  positional_index = ind_chunk + ind_within_chunk
162
- list_task_files[
163
- positional_index
164
- ].prefix = f"{MULTISUBMIT_PREFIX}-{positional_index:06d}"
165
139
  future = self.executor.submit(
166
140
  func,
167
141
  parameters=kwargs,
@@ -171,23 +145,6 @@ class LocalRunner(BaseRunner):
171
145
  )
172
146
  active_futures[positional_index] = future
173
147
 
174
- if task_type == "parallel":
175
- # FIXME: replace loop with a `bulk_update_history_unit`
176
- # function
177
- update_logfile_of_history_unit(
178
- history_unit_id=history_unit_ids[positional_index],
179
- logfile=list_task_files[
180
- positional_index
181
- ].log_file_local,
182
- )
183
- else:
184
- logger.debug(
185
- f"Unclear what logfile to associate to {task_type=} "
186
- "within multisubmit (see issue #2382)."
187
- )
188
- # FIXME: Improve definition for compound tasks
189
- pass
190
-
191
148
  while active_futures:
192
149
  finished_futures = [
193
150
  index_and_future
@@ -407,6 +407,10 @@ class SlurmConfig(BaseModel):
407
407
 
408
408
  return lines
409
409
 
410
+ @property
411
+ def batch_size(self) -> int:
412
+ return self.tasks_per_job
413
+
410
414
 
411
415
  def _parse_mem_value(raw_mem: Union[str, int]) -> int:
412
416
  """
@@ -12,7 +12,6 @@ import cloudpickle
12
12
  from ..slurm_common._slurm_config import SlurmConfig
13
13
  from ..slurm_common.slurm_job_task_models import SlurmJob
14
14
  from ..slurm_common.slurm_job_task_models import SlurmTask
15
- from ._batching import heuristics
16
15
  from ._job_states import STATES_FINISHED
17
16
  from fractal_server import __VERSION__
18
17
  from fractal_server.app.db import get_sync_db
@@ -20,15 +19,10 @@ from fractal_server.app.runner.exceptions import JobExecutionError
20
19
  from fractal_server.app.runner.exceptions import TaskExecutionError
21
20
  from fractal_server.app.runner.executors.base_runner import BaseRunner
22
21
  from fractal_server.app.runner.filenames import SHUTDOWN_FILENAME
23
- from fractal_server.app.runner.task_files import MULTISUBMIT_PREFIX
24
- from fractal_server.app.runner.task_files import SUBMIT_PREFIX
25
22
  from fractal_server.app.runner.task_files import TaskFiles
26
23
  from fractal_server.app.runner.v2.db_tools import (
27
24
  bulk_update_status_of_history_unit,
28
25
  )
29
- from fractal_server.app.runner.v2.db_tools import (
30
- update_logfile_of_history_unit,
31
- )
32
26
  from fractal_server.app.runner.v2.db_tools import update_status_of_history_unit
33
27
  from fractal_server.app.schemas.v2 import HistoryUnitStatus
34
28
  from fractal_server.config import get_settings
@@ -84,9 +78,18 @@ class BaseSlurmRunner(BaseRunner):
84
78
 
85
79
  # Create job folders. Note that the local one may or may not exist
86
80
  # depending on whether it is a test or an actual run
87
- if not self.root_dir_local.is_dir():
88
- self._mkdir_local_folder(self.root_dir_local.as_posix())
89
- self._mkdir_remote_folder(self.root_dir_remote.as_posix())
81
+ try:
82
+ if not self.root_dir_local.is_dir():
83
+ self._mkdir_local_folder(self.root_dir_local.as_posix())
84
+ self._mkdir_remote_folder(self.root_dir_remote.as_posix())
85
+ except Exception as e:
86
+ error_msg = (
87
+ f"Could not mkdir {self.root_dir_local.as_posix()} or "
88
+ f"{self.root_dir_remote.as_posix()}. "
89
+ f"Original error: {str(e)}."
90
+ )
91
+ logger.error(error_msg)
92
+ raise RuntimeError(error_msg)
90
93
 
91
94
  self.shutdown_file = self.root_dir_local / SHUTDOWN_FILENAME
92
95
  self.jobs = {}
@@ -178,7 +181,7 @@ class BaseSlurmRunner(BaseRunner):
178
181
  fractal_server=__VERSION__,
179
182
  )
180
183
  for task in slurm_job.tasks:
181
- # Wrinte input pickle
184
+ # Write input pickle
182
185
  _args = []
183
186
  _kwargs = dict(
184
187
  parameters=task.parameters,
@@ -485,21 +488,14 @@ class BaseSlurmRunner(BaseRunner):
485
488
  self._mkdir_remote_folder(folder=workdir_remote.as_posix())
486
489
  logger.info("[submit] Create local/remote folders - END")
487
490
 
488
- # Add prefix to task_files object
489
- task_files.prefix = SUBMIT_PREFIX
490
- update_logfile_of_history_unit(
491
- history_unit_id=history_unit_id,
492
- logfile=task_files.log_file_local,
493
- )
494
-
495
491
  # Submission phase
496
492
  slurm_job = SlurmJob(
497
- prefix=SUBMIT_PREFIX,
493
+ prefix=task_files.prefix,
498
494
  workdir_local=workdir_local,
499
495
  workdir_remote=workdir_remote,
500
496
  tasks=[
501
497
  SlurmTask(
502
- prefix=SUBMIT_PREFIX,
498
+ prefix=task_files.prefix,
503
499
  index=0,
504
500
  component=task_files.component,
505
501
  parameters=parameters,
@@ -575,6 +571,11 @@ class BaseSlurmRunner(BaseRunner):
575
571
  task_type: Literal["parallel", "compound", "converter_compound"],
576
572
  config: SlurmConfig,
577
573
  ) -> tuple[dict[int, Any], dict[int, BaseException]]:
574
+ """
575
+ Note: `list_parameters`, `list_task_files` and `history_unit_ids`
576
+ have the same size. For parallel tasks, this is also the number of
577
+ input images, while for compound tasks these can differ.
578
+ """
578
579
 
579
580
  if len(self.jobs) > 0:
580
581
  raise RuntimeError(
@@ -599,11 +600,7 @@ class BaseSlurmRunner(BaseRunner):
599
600
  list_parameters=list_parameters,
600
601
  task_type=task_type,
601
602
  list_task_files=list_task_files,
602
- )
603
- self.validate_multisubmit_history_unit_ids(
604
603
  history_unit_ids=history_unit_ids,
605
- task_type=task_type,
606
- list_parameters=list_parameters,
607
604
  )
608
605
 
609
606
  logger.info(f"[multisubmit] START, {len(list_parameters)=}")
@@ -624,46 +621,28 @@ class BaseSlurmRunner(BaseRunner):
624
621
 
625
622
  tot_tasks = len(list_parameters)
626
623
 
627
- # Set/validate parameters for task batching
628
- tasks_per_job, parallel_tasks_per_job = heuristics(
629
- # Number of parallel components (always known)
630
- tot_tasks=tot_tasks,
631
- # Optional WorkflowTask attributes:
632
- tasks_per_job=config.tasks_per_job,
633
- parallel_tasks_per_job=config.parallel_tasks_per_job, # noqa
634
- # Task requirements (multiple possible sources):
635
- cpus_per_task=config.cpus_per_task,
636
- mem_per_task=config.mem_per_task_MB,
637
- # Fractal configuration variables (soft/hard limits):
638
- target_cpus_per_job=config.target_cpus_per_job,
639
- target_mem_per_job=config.target_mem_per_job,
640
- target_num_jobs=config.target_num_jobs,
641
- max_cpus_per_job=config.max_cpus_per_job,
642
- max_mem_per_job=config.max_mem_per_job,
643
- max_num_jobs=config.max_num_jobs,
644
- )
645
- config.parallel_tasks_per_job = parallel_tasks_per_job
646
- config.tasks_per_job = tasks_per_job
624
+ # NOTE: chunking has already taken place in `get_slurm_config`,
625
+ # so that `config.tasks_per_job` is now set.
647
626
 
648
627
  # Divide arguments in batches of `tasks_per_job` tasks each
649
628
  args_batches = []
650
- batch_size = tasks_per_job
629
+ batch_size = config.tasks_per_job
651
630
  for ind_chunk in range(0, tot_tasks, batch_size):
652
631
  args_batches.append(
653
632
  list_parameters[ind_chunk : ind_chunk + batch_size] # noqa
654
633
  )
655
- if len(args_batches) != math.ceil(tot_tasks / tasks_per_job):
634
+ if len(args_batches) != math.ceil(tot_tasks / config.tasks_per_job):
656
635
  raise RuntimeError("Something wrong here while batching tasks")
657
636
 
658
637
  # Part 1/3: Iterate over chunks, prepare SlurmJob objects
659
638
  logger.info("[multisubmit] Prepare `SlurmJob`s.")
660
639
  jobs_to_submit = []
661
640
  for ind_batch, chunk in enumerate(args_batches):
662
- prefix = f"{MULTISUBMIT_PREFIX}-{ind_batch:06d}"
641
+ # Read prefix based on the first task of this batch
642
+ prefix = list_task_files[ind_batch * batch_size].prefix
663
643
  tasks = []
664
644
  for ind_chunk, parameters in enumerate(chunk):
665
645
  index = (ind_batch * batch_size) + ind_chunk
666
- list_task_files[index].prefix = prefix
667
646
  tasks.append(
668
647
  SlurmTask(
669
648
  prefix=prefix,
@@ -676,7 +655,6 @@ class BaseSlurmRunner(BaseRunner):
676
655
  task_files=list_task_files[index],
677
656
  ),
678
657
  )
679
-
680
658
  jobs_to_submit.append(
681
659
  SlurmJob(
682
660
  prefix=prefix,
@@ -697,21 +675,6 @@ class BaseSlurmRunner(BaseRunner):
697
675
  slurm_config=config,
698
676
  )
699
677
 
700
- if task_type == "parallel":
701
- # FIXME: replace loop with a `bulk_update_history_unit` function
702
- for ind, task_files in enumerate(list_task_files):
703
- update_logfile_of_history_unit(
704
- history_unit_id=history_unit_ids[ind],
705
- logfile=task_files.log_file_local,
706
- )
707
- else:
708
- logger.debug(
709
- f"Unclear what logfile to associate to {task_type=} "
710
- "within multisubmit (see issue #2382)."
711
- )
712
- # FIXME: Improve definition for compound tasks
713
- pass
714
-
715
678
  logger.info(f"END submission phase, {self.job_ids=}")
716
679
 
717
680
  # FIXME: replace this sleep with a more precise check
@@ -2,6 +2,7 @@ from pathlib import Path
2
2
  from typing import Literal
3
3
  from typing import Optional
4
4
 
5
+ from ._batching import heuristics
5
6
  from ._slurm_config import _parse_mem_value
6
7
  from ._slurm_config import load_slurm_config_file
7
8
  from ._slurm_config import logger
@@ -10,7 +11,7 @@ from ._slurm_config import SlurmConfigError
10
11
  from fractal_server.app.models.v2 import WorkflowTaskV2
11
12
 
12
13
 
13
- def get_slurm_config(
14
+ def get_slurm_config_internal(
14
15
  wftask: WorkflowTaskV2,
15
16
  which_type: Literal["non_parallel", "parallel"],
16
17
  config_path: Optional[Path] = None,
@@ -162,3 +163,39 @@ def get_slurm_config(
162
163
  slurm_config = SlurmConfig(**slurm_dict)
163
164
 
164
165
  return slurm_config
166
+
167
+
168
+ def get_slurm_config(
169
+ wftask: WorkflowTaskV2,
170
+ which_type: Literal["non_parallel", "parallel"],
171
+ config_path: Optional[Path] = None,
172
+ tot_tasks: int = 1,
173
+ ) -> SlurmConfig:
174
+ config = get_slurm_config_internal(
175
+ wftask,
176
+ which_type,
177
+ config_path,
178
+ )
179
+
180
+ # Set/validate parameters for task batching
181
+ tasks_per_job, parallel_tasks_per_job = heuristics(
182
+ # Number of parallel components (always known)
183
+ tot_tasks=tot_tasks,
184
+ # Optional WorkflowTask attributes:
185
+ tasks_per_job=config.tasks_per_job,
186
+ parallel_tasks_per_job=config.parallel_tasks_per_job, # noqa
187
+ # Task requirements (multiple possible sources):
188
+ cpus_per_task=config.cpus_per_task,
189
+ mem_per_task=config.mem_per_task_MB,
190
+ # Fractal configuration variables (soft/hard limits):
191
+ target_cpus_per_job=config.target_cpus_per_job,
192
+ target_mem_per_job=config.target_mem_per_job,
193
+ target_num_jobs=config.target_num_jobs,
194
+ max_cpus_per_job=config.max_cpus_per_job,
195
+ max_mem_per_job=config.max_mem_per_job,
196
+ max_num_jobs=config.max_num_jobs,
197
+ )
198
+ config.parallel_tasks_per_job = parallel_tasks_per_job
199
+ config.tasks_per_job = tasks_per_job
200
+
201
+ return config
@@ -4,6 +4,7 @@ from typing import Union
4
4
 
5
5
  from pydantic import BaseModel
6
6
 
7
+ from fractal_server.app.runner.components import _index_to_component
7
8
  from fractal_server.string_tools import sanitize_string
8
9
 
9
10
  SUBMIT_PREFIX = "non_par"
@@ -140,3 +141,31 @@ class TaskFiles(BaseModel):
140
141
  metadiff_file_remote=self.metadiff_file_remote,
141
142
  log_file_remote=self.log_file_remote,
142
143
  )
144
+
145
+
146
+ def enrich_task_files_multisubmit(
147
+ *,
148
+ tot_tasks: int,
149
+ batch_size: int,
150
+ base_task_files: TaskFiles,
151
+ ) -> list[TaskFiles]:
152
+ """
153
+ Expand `TaskFiles` objects with `component` and `prefix`.
154
+ """
155
+
156
+ new_list_task_files: list[TaskFiles] = []
157
+ for absolute_index in range(tot_tasks):
158
+ ind_batch = absolute_index // batch_size
159
+ new_list_task_files.append(
160
+ TaskFiles(
161
+ **base_task_files.model_dump(
162
+ exclude={
163
+ "component",
164
+ "prefix",
165
+ }
166
+ ),
167
+ prefix=f"{MULTISUBMIT_PREFIX}-{ind_batch:06d}",
168
+ component=_index_to_component(absolute_index),
169
+ )
170
+ )
171
+ return new_list_task_files
@@ -4,7 +4,6 @@ from sqlalchemy.dialects.postgresql import insert as pg_insert
4
4
  from sqlalchemy.orm import Session
5
5
  from sqlmodel import update
6
6
 
7
- from fractal_server.app.db import get_sync_db
8
7
  from fractal_server.app.models.v2 import HistoryImageCache
9
8
  from fractal_server.app.models.v2 import HistoryRun
10
9
  from fractal_server.app.models.v2 import HistoryUnit
@@ -59,20 +58,6 @@ def bulk_update_status_of_history_unit(
59
58
  db_sync.commit()
60
59
 
61
60
 
62
- def update_logfile_of_history_unit(
63
- *,
64
- history_unit_id: int,
65
- logfile: str,
66
- ) -> None:
67
- with next(get_sync_db()) as db_sync:
68
- unit = db_sync.get(HistoryUnit, history_unit_id)
69
- if unit is None:
70
- raise ValueError(f"HistoryUnit {history_unit_id} not found.")
71
- unit.logfile = logfile
72
- db_sync.merge(unit)
73
- db_sync.commit()
74
-
75
-
76
61
  def bulk_upsert_image_cache_fast(
77
62
  *,
78
63
  list_upsert_objects: list[dict[str, Any]],
@@ -128,10 +128,6 @@ def execute_tasks_v2(
128
128
  db.commit()
129
129
  db.refresh(history_run)
130
130
  history_run_id = history_run.id
131
- logger.debug(
132
- f"Created {history_run_id=}, for "
133
- f"{wftask.id=} and {dataset.id=}"
134
- )
135
131
 
136
132
  # TASK EXECUTION (V2)
137
133
  if task.type in ["non_parallel", "converter_non_parallel"]:
@@ -205,9 +201,9 @@ def execute_tasks_v2(
205
201
  # Update image list
206
202
  num_new_images = 0
207
203
  current_task_output.check_zarr_urls_are_unique()
208
- # FIXME: Introduce for loop over task outputs, and processe them
209
- # sequentially
210
- # each failure should lead to an update of the specific image status
204
+ # NOTE: In principle we could make the task-output processing more
205
+ # granular, and also associate output-processing failures to history
206
+ # status.
211
207
  for image_obj in current_task_output.image_list_updates:
212
208
  image = image_obj.model_dump()
213
209
  # Edit existing image
@@ -346,7 +342,7 @@ def execute_tasks_v2(
346
342
  )
347
343
 
348
344
  db.commit()
349
- db.close() # FIXME: why is this needed?
345
+ db.close() # NOTE: this is needed, but the reason is unclear
350
346
 
351
347
  # Create accounting record
352
348
  record = AccountingRecord(