fractal-server 2.12.1__py3-none-any.whl → 2.13.1__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.
- fractal_server/__init__.py +1 -1
- fractal_server/app/models/security.py +9 -12
- fractal_server/app/models/v2/__init__.py +4 -0
- fractal_server/app/models/v2/accounting.py +35 -0
- fractal_server/app/models/v2/dataset.py +2 -2
- fractal_server/app/models/v2/job.py +11 -9
- fractal_server/app/models/v2/task.py +2 -3
- fractal_server/app/models/v2/task_group.py +6 -2
- fractal_server/app/models/v2/workflowtask.py +15 -8
- fractal_server/app/routes/admin/v2/__init__.py +4 -0
- fractal_server/app/routes/admin/v2/accounting.py +108 -0
- fractal_server/app/routes/admin/v2/impersonate.py +35 -0
- fractal_server/app/routes/admin/v2/job.py +5 -13
- fractal_server/app/routes/admin/v2/task.py +1 -1
- fractal_server/app/routes/admin/v2/task_group.py +5 -13
- fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +3 -3
- fractal_server/app/routes/api/v2/dataset.py +4 -4
- fractal_server/app/routes/api/v2/images.py +11 -11
- fractal_server/app/routes/api/v2/project.py +2 -2
- fractal_server/app/routes/api/v2/status.py +1 -1
- fractal_server/app/routes/api/v2/submit.py +9 -6
- fractal_server/app/routes/api/v2/task.py +4 -2
- fractal_server/app/routes/api/v2/task_collection.py +3 -2
- fractal_server/app/routes/api/v2/task_group.py +4 -7
- fractal_server/app/routes/api/v2/workflow.py +3 -3
- fractal_server/app/routes/api/v2/workflow_import.py +3 -3
- fractal_server/app/routes/api/v2/workflowtask.py +3 -1
- fractal_server/app/routes/auth/_aux_auth.py +4 -1
- fractal_server/app/routes/auth/current_user.py +3 -5
- fractal_server/app/routes/auth/group.py +1 -1
- fractal_server/app/routes/auth/users.py +2 -4
- fractal_server/app/routes/aux/__init__.py +0 -20
- fractal_server/app/routes/aux/_runner.py +1 -1
- fractal_server/app/routes/aux/validate_user_settings.py +1 -2
- fractal_server/app/runner/executors/_job_states.py +13 -0
- fractal_server/app/runner/executors/slurm/_slurm_config.py +26 -18
- fractal_server/app/runner/executors/slurm/ssh/__init__.py +0 -3
- fractal_server/app/runner/executors/slurm/ssh/_executor_wait_thread.py +31 -22
- fractal_server/app/runner/executors/slurm/ssh/_slurm_job.py +2 -5
- fractal_server/app/runner/executors/slurm/ssh/executor.py +21 -27
- fractal_server/app/runner/executors/slurm/sudo/__init__.py +0 -3
- fractal_server/app/runner/executors/slurm/sudo/_check_jobs_status.py +1 -2
- fractal_server/app/runner/executors/slurm/sudo/_executor_wait_thread.py +37 -47
- fractal_server/app/runner/executors/slurm/sudo/executor.py +25 -24
- fractal_server/app/runner/v2/__init__.py +4 -9
- fractal_server/app/runner/v2/_local/__init__.py +3 -0
- fractal_server/app/runner/v2/_local/_local_config.py +5 -4
- fractal_server/app/runner/v2/_slurm_common/get_slurm_config.py +4 -4
- fractal_server/app/runner/v2/_slurm_ssh/__init__.py +2 -0
- fractal_server/app/runner/v2/_slurm_sudo/__init__.py +4 -2
- fractal_server/app/runner/v2/deduplicate_list.py +1 -1
- fractal_server/app/runner/v2/runner.py +25 -10
- fractal_server/app/runner/v2/runner_functions.py +12 -11
- fractal_server/app/runner/v2/task_interface.py +15 -7
- fractal_server/app/schemas/_filter_validators.py +6 -3
- fractal_server/app/schemas/_validators.py +7 -5
- fractal_server/app/schemas/user.py +23 -18
- fractal_server/app/schemas/user_group.py +25 -11
- fractal_server/app/schemas/user_settings.py +31 -24
- fractal_server/app/schemas/v2/__init__.py +1 -0
- fractal_server/app/schemas/v2/accounting.py +18 -0
- fractal_server/app/schemas/v2/dataset.py +48 -35
- fractal_server/app/schemas/v2/dumps.py +16 -14
- fractal_server/app/schemas/v2/job.py +49 -29
- fractal_server/app/schemas/v2/manifest.py +32 -28
- fractal_server/app/schemas/v2/project.py +18 -8
- fractal_server/app/schemas/v2/task.py +86 -75
- fractal_server/app/schemas/v2/task_collection.py +41 -30
- fractal_server/app/schemas/v2/task_group.py +39 -20
- fractal_server/app/schemas/v2/workflow.py +24 -12
- fractal_server/app/schemas/v2/workflowtask.py +63 -61
- fractal_server/app/security/__init__.py +1 -1
- fractal_server/config.py +86 -73
- fractal_server/images/models.py +18 -12
- fractal_server/main.py +1 -1
- fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +57 -0
- fractal_server/tasks/v2/utils_background.py +2 -2
- fractal_server/tasks/v2/utils_database.py +1 -1
- {fractal_server-2.12.1.dist-info → fractal_server-2.13.1.dist-info}/METADATA +9 -10
- {fractal_server-2.12.1.dist-info → fractal_server-2.13.1.dist-info}/RECORD +83 -81
- fractal_server/app/runner/v2/_local_experimental/__init__.py +0 -121
- fractal_server/app/runner/v2/_local_experimental/_local_config.py +0 -108
- fractal_server/app/runner/v2/_local_experimental/_submit_setup.py +0 -42
- fractal_server/app/runner/v2/_local_experimental/executor.py +0 -157
- {fractal_server-2.12.1.dist-info → fractal_server-2.13.1.dist-info}/LICENSE +0 -0
- {fractal_server-2.12.1.dist-info → fractal_server-2.13.1.dist-info}/WHEEL +0 -0
- {fractal_server-2.12.1.dist-info → fractal_server-2.13.1.dist-info}/entry_points.txt +0 -0
@@ -1,42 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Submodule to define _local_submit_setup
|
3
|
-
"""
|
4
|
-
from pathlib import Path
|
5
|
-
from typing import Literal
|
6
|
-
from typing import Optional
|
7
|
-
|
8
|
-
from ....models.v2 import WorkflowTaskV2
|
9
|
-
from ._local_config import get_local_backend_config
|
10
|
-
|
11
|
-
|
12
|
-
def _local_submit_setup(
|
13
|
-
*,
|
14
|
-
wftask: WorkflowTaskV2,
|
15
|
-
workflow_dir_local: Optional[Path] = None,
|
16
|
-
workflow_dir_remote: Optional[Path] = None,
|
17
|
-
which_type: Literal["non_parallel", "parallel"],
|
18
|
-
) -> dict[str, object]:
|
19
|
-
"""
|
20
|
-
Collect WorfklowTask-specific configuration parameters from different
|
21
|
-
sources, and inject them for execution.
|
22
|
-
|
23
|
-
Arguments:
|
24
|
-
wftask:
|
25
|
-
WorkflowTask for which the configuration is to be assembled
|
26
|
-
workflow_dir_local:
|
27
|
-
Not used in this function.
|
28
|
-
workflow_dir_remote:
|
29
|
-
Not used in this function.
|
30
|
-
|
31
|
-
Returns:
|
32
|
-
submit_setup_dict:
|
33
|
-
A dictionary that will be passed on to
|
34
|
-
`FractalProcessPoolExecutor.submit` and
|
35
|
-
`FractalProcessPoolExecutor.map`, so as to set extra options.
|
36
|
-
"""
|
37
|
-
|
38
|
-
local_backend_config = get_local_backend_config(
|
39
|
-
wftask=wftask, which_type=which_type
|
40
|
-
)
|
41
|
-
|
42
|
-
return dict(local_backend_config=local_backend_config)
|
@@ -1,157 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Custom version of Python
|
3
|
-
[ProcessPoolExecutor](https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor)).
|
4
|
-
"""
|
5
|
-
import multiprocessing as mp
|
6
|
-
import threading
|
7
|
-
import time
|
8
|
-
from concurrent.futures import ProcessPoolExecutor
|
9
|
-
from concurrent.futures.process import BrokenProcessPool
|
10
|
-
from pathlib import Path
|
11
|
-
from typing import Callable
|
12
|
-
from typing import Iterable
|
13
|
-
from typing import Optional
|
14
|
-
from typing import Sequence
|
15
|
-
|
16
|
-
import psutil
|
17
|
-
|
18
|
-
from ._local_config import get_default_local_backend_config
|
19
|
-
from ._local_config import LocalBackendConfig
|
20
|
-
from fractal_server.app.runner.exceptions import JobExecutionError
|
21
|
-
from fractal_server.logger import set_logger
|
22
|
-
|
23
|
-
logger = set_logger("FractalProcessPoolExecutor")
|
24
|
-
|
25
|
-
|
26
|
-
class FractalProcessPoolExecutor(ProcessPoolExecutor):
|
27
|
-
|
28
|
-
shutdown_file: Path
|
29
|
-
interval: float
|
30
|
-
_shutdown: bool
|
31
|
-
_shutdown_file_thread: threading.Thread
|
32
|
-
|
33
|
-
def __init__(
|
34
|
-
self, shutdown_file: Path, interval: float = 1.0, *args, **kwargs
|
35
|
-
):
|
36
|
-
super().__init__(*args, **kwargs, mp_context=mp.get_context("spawn"))
|
37
|
-
self.shutdown_file = Path(shutdown_file)
|
38
|
-
self.interval = float(interval)
|
39
|
-
logger.debug(
|
40
|
-
f"Start monitoring {shutdown_file} every {interval} seconds"
|
41
|
-
)
|
42
|
-
self._shutdown = False
|
43
|
-
self._shutdown_file_thread = threading.Thread(
|
44
|
-
target=self._run, daemon=True
|
45
|
-
)
|
46
|
-
self._shutdown_file_thread.start()
|
47
|
-
|
48
|
-
def _run(self):
|
49
|
-
"""
|
50
|
-
Running on '_shutdown_file_thread'.
|
51
|
-
"""
|
52
|
-
while True:
|
53
|
-
if self.shutdown_file.exists() or self._shutdown:
|
54
|
-
try:
|
55
|
-
self._terminate_processes()
|
56
|
-
except Exception as e:
|
57
|
-
logger.error(
|
58
|
-
"Terminate processes failed. "
|
59
|
-
f"Original error: {str(e)}."
|
60
|
-
)
|
61
|
-
finally:
|
62
|
-
return
|
63
|
-
time.sleep(self.interval)
|
64
|
-
|
65
|
-
def _terminate_processes(self):
|
66
|
-
"""
|
67
|
-
Running on '_shutdown_file_thread'.
|
68
|
-
"""
|
69
|
-
|
70
|
-
logger.info("Start terminating FractalProcessPoolExecutor processes.")
|
71
|
-
# We use 'psutil' in order to easily access the PIDs of the children.
|
72
|
-
if self._processes is not None:
|
73
|
-
for pid in self._processes.keys():
|
74
|
-
parent = psutil.Process(pid)
|
75
|
-
children = parent.children(recursive=True)
|
76
|
-
for child in children:
|
77
|
-
child.kill()
|
78
|
-
parent.kill()
|
79
|
-
logger.info(f"Process {pid} and its children terminated.")
|
80
|
-
logger.info("FractalProcessPoolExecutor processes terminated.")
|
81
|
-
|
82
|
-
def shutdown(self, *args, **kwargs) -> None:
|
83
|
-
self._shutdown = True
|
84
|
-
self._shutdown_file_thread.join()
|
85
|
-
return super().shutdown(*args, **kwargs)
|
86
|
-
|
87
|
-
def submit(
|
88
|
-
self,
|
89
|
-
*args,
|
90
|
-
local_backend_config: Optional[LocalBackendConfig] = None,
|
91
|
-
**kwargs,
|
92
|
-
):
|
93
|
-
"""
|
94
|
-
Compared to the `ProcessPoolExecutor` method, here we accept an
|
95
|
-
additional keyword argument (`local_backend_config`), which is then
|
96
|
-
simply ignored.
|
97
|
-
"""
|
98
|
-
return super().submit(*args, **kwargs)
|
99
|
-
|
100
|
-
def map(
|
101
|
-
self,
|
102
|
-
fn: Callable,
|
103
|
-
*iterables: Sequence[Iterable],
|
104
|
-
local_backend_config: Optional[LocalBackendConfig] = None,
|
105
|
-
):
|
106
|
-
"""
|
107
|
-
Custom version of the `Executor.map` method
|
108
|
-
|
109
|
-
The main change with the respect to the original `map` method is that
|
110
|
-
the list of tasks to be executed is split into chunks, and then
|
111
|
-
`super().map` is called (sequentially) on each chunk. The goal of this
|
112
|
-
change is to limit parallelism, e.g. due to limited computational
|
113
|
-
resources.
|
114
|
-
|
115
|
-
Other changes from the `concurrent.futures` `map` method:
|
116
|
-
|
117
|
-
1. Removed `timeout` argument;
|
118
|
-
2. Removed `chunksize`;
|
119
|
-
3. All iterators (both inputs and output ones) are transformed into
|
120
|
-
lists.
|
121
|
-
|
122
|
-
Args:
|
123
|
-
fn: A callable function.
|
124
|
-
iterables: The argument iterables (one iterable per argument of
|
125
|
-
`fn`).
|
126
|
-
local_backend_config: The backend configuration, needed to extract
|
127
|
-
`parallel_tasks_per_job`.
|
128
|
-
"""
|
129
|
-
# Preliminary check
|
130
|
-
iterable_lengths = [len(it) for it in iterables]
|
131
|
-
if not len(set(iterable_lengths)) == 1:
|
132
|
-
raise ValueError("Iterables have different lengths.")
|
133
|
-
# Set total number of arguments
|
134
|
-
n_elements = len(iterables[0])
|
135
|
-
|
136
|
-
# Set parallel_tasks_per_job
|
137
|
-
if local_backend_config is None:
|
138
|
-
local_backend_config = get_default_local_backend_config()
|
139
|
-
parallel_tasks_per_job = local_backend_config.parallel_tasks_per_job
|
140
|
-
if parallel_tasks_per_job is None:
|
141
|
-
parallel_tasks_per_job = n_elements
|
142
|
-
|
143
|
-
# Execute tasks, in chunks of size parallel_tasks_per_job
|
144
|
-
results = []
|
145
|
-
for ind_chunk in range(0, n_elements, parallel_tasks_per_job):
|
146
|
-
chunk_iterables = [
|
147
|
-
it[ind_chunk : ind_chunk + parallel_tasks_per_job] # noqa
|
148
|
-
for it in iterables
|
149
|
-
]
|
150
|
-
map_iter = super().map(fn, *chunk_iterables)
|
151
|
-
|
152
|
-
try:
|
153
|
-
results.extend(list(map_iter))
|
154
|
-
except BrokenProcessPool as e:
|
155
|
-
raise JobExecutionError(info=e.args[0])
|
156
|
-
|
157
|
-
return iter(results)
|
File without changes
|
File without changes
|
File without changes
|