fractal-server 2.9.0a1__py3-none-any.whl → 2.9.0a2__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.
@@ -1 +1 @@
1
- __VERSION__ = "2.9.0a1"
1
+ __VERSION__ = "2.9.0a2"
@@ -48,6 +48,10 @@ class TaskGroupV2(SQLModel, table=True):
48
48
  default_factory=get_timestamp,
49
49
  sa_column=Column(DateTime(timezone=True), nullable=False),
50
50
  )
51
+ timestamp_last_used: Optional[datetime] = Field(
52
+ default=None,
53
+ sa_column=Column(DateTime(timezone=True), nullable=True),
54
+ )
51
55
 
52
56
  @property
53
57
  def pip_install_string(self) -> str:
@@ -30,6 +30,7 @@ from ...aux.validate_user_settings import validate_user_settings
30
30
  from ._aux_functions import _get_dataset_check_owner
31
31
  from ._aux_functions import _get_workflow_check_owner
32
32
  from ._aux_functions import clean_app_job_list_v2
33
+ from fractal_server.app.models import TaskGroupV2
33
34
  from fractal_server.app.models import UserOAuth
34
35
  from fractal_server.app.routes.api.v2._aux_functions_tasks import (
35
36
  _get_task_read_access,
@@ -61,6 +62,8 @@ async def apply_workflow(
61
62
  db: AsyncSession = Depends(get_async_db),
62
63
  ) -> Optional[JobReadV2]:
63
64
 
65
+ now = get_timestamp()
66
+
64
67
  # Remove non-submitted V2 jobs from the app state when the list grows
65
68
  # beyond a threshold
66
69
  settings = Inject(get_settings)
@@ -112,22 +115,23 @@ async def apply_workflow(
112
115
  )
113
116
 
114
117
  # Check that tasks have read-access and are `active`
118
+ used_task_group_ids = set()
115
119
  for wftask in workflow.task_list[
116
120
  first_task_index : last_task_index + 1 # noqa: E203
117
121
  ]:
118
- await _get_task_read_access(
122
+ task = await _get_task_read_access(
119
123
  user_id=user.id,
120
124
  task_id=wftask.task_id,
121
125
  require_active=True,
122
126
  db=db,
123
127
  )
128
+ used_task_group_ids.add(task.taskgroupv2_id)
124
129
 
125
130
  # Validate user settings
126
131
  FRACTAL_RUNNER_BACKEND = settings.FRACTAL_RUNNER_BACKEND
127
132
  user_settings = await validate_user_settings(
128
133
  user=user, backend=FRACTAL_RUNNER_BACKEND, db=db
129
134
  )
130
-
131
135
  # Check that no other job with the same dataset_id is SUBMITTED
132
136
  stm = (
133
137
  select(JobV2)
@@ -184,8 +188,18 @@ async def apply_workflow(
184
188
  await db.commit()
185
189
  await db.refresh(job)
186
190
 
191
+ # Update TaskGroupV2.timestamp_last_used
192
+ res = await db.execute(
193
+ select(TaskGroupV2).where(TaskGroupV2.id.in_(used_task_group_ids))
194
+ )
195
+ used_task_groups = res.scalars().all()
196
+ for used_task_group in used_task_groups:
197
+ used_task_group.timestamp_last_used = now
198
+ db.add(used_task_group)
199
+ await db.commit()
200
+
187
201
  # Define server-side job directory
188
- timestamp_string = get_timestamp().strftime("%Y%m%d_%H%M%S")
202
+ timestamp_string = now.strftime("%Y%m%d_%H%M%S")
189
203
  WORKFLOW_DIR_LOCAL = settings.FRACTAL_RUNNER_WORKING_BASE_DIR / (
190
204
  f"proj_v2_{project_id:07d}_wf_{workflow_id:07d}_job_{job.id:07d}"
191
205
  f"_{timestamp_string}"
@@ -89,6 +89,7 @@ class TaskGroupReadV2(BaseModel):
89
89
 
90
90
  active: bool
91
91
  timestamp_created: datetime
92
+ timestamp_last_used: Optional[datetime] = None
92
93
 
93
94
 
94
95
  class TaskGroupUpdateV2(BaseModel, extra=Extra.forbid):
@@ -67,6 +67,13 @@ def upgrade() -> None:
67
67
  batch_op.add_column(
68
68
  sa.Column("venv_file_number", sa.Integer(), nullable=True)
69
69
  )
70
+ batch_op.add_column(
71
+ sa.Column(
72
+ "timestamp_last_used",
73
+ sa.DateTime(timezone=True),
74
+ nullable=True,
75
+ )
76
+ )
70
77
 
71
78
  # ### end Alembic commands ###
72
79
 
@@ -74,6 +81,7 @@ def upgrade() -> None:
74
81
  def downgrade() -> None:
75
82
  # ### commands auto generated by Alembic - please adjust! ###
76
83
  with op.batch_alter_table("taskgroupv2", schema=None) as batch_op:
84
+ batch_op.drop_column("timestamp_last_used")
77
85
  batch_op.drop_column("venv_file_number")
78
86
  batch_op.drop_column("venv_size_in_kB")
79
87
  batch_op.drop_column("pip_freeze")
@@ -196,23 +196,57 @@ class FractalSSH(object):
196
196
  """
197
197
  Open the SSH connection and handle exceptions.
198
198
 
199
- This function can be called from within other functions that use
200
- `connection`, so that we can provide a meaningful error in case the
201
- SSH connection cannot be opened.
199
+ This method should always be called at the beginning of background
200
+ operations that use FractalSSH, so that:
201
+
202
+ 1. We try to restore unusable connections (e.g. due to closed socket).
203
+ 2. We provide an informative error if connection cannot be established.
202
204
  """
203
- if not self._connection.is_connected:
205
+ self.logger.debug(
206
+ f"[check_connection] {self._connection.is_connected=}"
207
+ )
208
+ if self._connection.is_connected:
209
+ # Even if the connection appears open, it could be broken for
210
+ # external reasons (e.g. the socket is closed because the SSH
211
+ # server was restarted). In these cases, we catch the error and
212
+ # try to re-open the connection.
204
213
  try:
205
- with _acquire_lock_with_timeout(
206
- lock=self._lock,
207
- label="_connection.open",
208
- timeout=self.default_lock_timeout,
209
- ):
210
- self._connection.open()
211
- except Exception as e:
212
- raise RuntimeError(
213
- f"Cannot open SSH connection. Original error:\n{str(e)}"
214
+ self.logger.info(
215
+ "[check_connection] Run dummy command to check connection."
216
+ )
217
+ # Run both an SFTP and an SSH command, as they correspond to
218
+ # different sockets
219
+ self.remote_exists("/dummy/path/")
220
+ self.run_command(cmd="whoami")
221
+ self.logger.info(
222
+ "[check_connection] SSH connection is already OK, exit."
223
+ )
224
+ return
225
+ except (OSError, EOFError) as e:
226
+ self.logger.warning(
227
+ f"[check_connection] Detected error {str(e)}, re-open."
228
+ )
229
+ # Try opening the connection (if it was closed) or to re-open it (if
230
+ # an error happened).
231
+ try:
232
+ self.close()
233
+ with _acquire_lock_with_timeout(
234
+ lock=self._lock,
235
+ label="_connection.open",
236
+ timeout=self.default_lock_timeout,
237
+ logger_name=self.logger_name,
238
+ ):
239
+ self._connection.open()
240
+ self._connection.client.open_sftp()
241
+ self.logger.info(
242
+ "[check_connection] SSH connection opened, exit."
214
243
  )
215
244
 
245
+ except Exception as e:
246
+ raise RuntimeError(
247
+ f"Cannot open SSH connection. Original error:\n{str(e)}"
248
+ )
249
+
216
250
  def close(self) -> None:
217
251
  """
218
252
  Aggressively close `self._connection`.
@@ -228,9 +262,8 @@ class FractalSSH(object):
228
262
  timeout=self.default_lock_timeout,
229
263
  ):
230
264
  self._connection.close()
231
-
232
- if self._connection.client is not None:
233
- self._connection.client.close()
265
+ if self._connection.client is not None:
266
+ self._connection.client.close()
234
267
 
235
268
  def run_command(
236
269
  self,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fractal-server
3
- Version: 2.9.0a1
3
+ Version: 2.9.0a2
4
4
  Summary: Server component of the Fractal analytics platform
5
5
  Home-page: https://github.com/fractal-analytics-platform/fractal-server
6
6
  License: BSD-3-Clause
@@ -1,4 +1,4 @@
1
- fractal_server/__init__.py,sha256=6M5YgTZyA5QmDsgSes9Ql2kogbZ0I5tDiCgSD49xIok,24
1
+ fractal_server/__init__.py,sha256=d0Y48obcx61ZaWA7ZS1o1kdZRZ6sJMhUfuKDOT5xPKU,24
2
2
  fractal_server/__main__.py,sha256=dEkCfzLLQrIlxsGC-HBfoR-RBMWnJDgNrxYTyzmE9c0,6146
3
3
  fractal_server/alembic.ini,sha256=MWwi7GzjzawI9cCAK1LW7NxIBQDUqD12-ptJoq5JpP0,3153
4
4
  fractal_server/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -20,7 +20,7 @@ fractal_server/app/models/v2/dataset.py,sha256=-7sxHEw4IIAvF_uSan7tA3o8hvoakBkQ0
20
20
  fractal_server/app/models/v2/job.py,sha256=ypJmN-qspkKBGhBG7Mt-HypSQqcQ2EmB4Bzzb2-y550,1535
21
21
  fractal_server/app/models/v2/project.py,sha256=rAHoh5KfYwIaW7rTX0_O0jvWmxEvfo1BafvmcXuSSRk,786
22
22
  fractal_server/app/models/v2/task.py,sha256=jebD28Pz8tGcsWCItxj6uKjcD8BMMnnU8dqYhvhEB6c,1520
23
- fractal_server/app/models/v2/task_group.py,sha256=X2Qlg-at2RcbvlWbpEMT3kZCk5WOVmJ6cOnKF-RDnQ0,3107
23
+ fractal_server/app/models/v2/task_group.py,sha256=Lxtwxk6pfffM8IehqkFvhDuecSXnXqTWeUlf7Y78oss,3254
24
24
  fractal_server/app/models/v2/workflow.py,sha256=YBgFGCziUgU0aJ5EM3Svu9W2c46AewZO9VBlFCHiSps,1069
25
25
  fractal_server/app/models/v2/workflowtask.py,sha256=iDuJYk8kp4PNqGmbKRtGI7y-QsbjkNd_gDsbMzL4i-g,1274
26
26
  fractal_server/app/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -50,7 +50,7 @@ fractal_server/app/routes/api/v2/images.py,sha256=JR1rR6qEs81nacjriOXAOBQjAbCXF4
50
50
  fractal_server/app/routes/api/v2/job.py,sha256=Bga2Kz1OjvDIdxZObWaaXVhNIhC_5JKhKRjEH2_ayEE,5157
51
51
  fractal_server/app/routes/api/v2/project.py,sha256=eWYFJ7F2ZYQcpi-_n-rhPF-Q4gJhzYBsVGYFhHZZXAE,6653
52
52
  fractal_server/app/routes/api/v2/status.py,sha256=6N9DSZ4iFqbZImorWfEAPoyoFUgEruo4Hweqo0x0xXU,6435
53
- fractal_server/app/routes/api/v2/submit.py,sha256=tq-NGnUlpIcm_MRN47rJRHkRcIJ5HiL4Wj1wItJy3o8,8185
53
+ fractal_server/app/routes/api/v2/submit.py,sha256=jqYix7X6dUJn8w6RWasu1lOFf7T_CcXQlpVY38njE24,8688
54
54
  fractal_server/app/routes/api/v2/task.py,sha256=K0ik33t7vL8BAK5S7fqyJDNdRK4stGqb_73bSa8tvPE,7159
55
55
  fractal_server/app/routes/api/v2/task_collection.py,sha256=-DVhultvdI3Jh8Jq8W5np6Lnkh5oisjbKCwxFmwddmo,9820
56
56
  fractal_server/app/routes/api/v2/task_collection_custom.py,sha256=cctW61-C2QYF2KXluS15lLhZJS_kt30Ca6UGLFO32z0,6207
@@ -157,7 +157,7 @@ fractal_server/app/schemas/v2/project.py,sha256=UXEA0UUUe0bFFOVLLmVtvDFLBO5vmD1J
157
157
  fractal_server/app/schemas/v2/status.py,sha256=SQaUpQkjFq5c5k5J4rOjNhuQaDOEg8lksPhkKmPU5VU,332
158
158
  fractal_server/app/schemas/v2/task.py,sha256=FFAbYwDlqowB8gVMdjFVPVHvAM0T89PYLixUth49xfQ,6870
159
159
  fractal_server/app/schemas/v2/task_collection.py,sha256=yHpCRxoj6tKqCiQfUjaTj8SfCn1ChD_P6okfEOzyUDE,6518
160
- fractal_server/app/schemas/v2/task_group.py,sha256=HbwWTabPXaND8cawJnCvOm8S89uYwQUzJJWXWKLQ63A,2963
160
+ fractal_server/app/schemas/v2/task_group.py,sha256=e4NwFuOmiO0afoZLVsI_XHIpD_o_QWDpzlI7ZoNAYwo,3014
161
161
  fractal_server/app/schemas/v2/workflow.py,sha256=HSNQSrBRdoBzh8Igr76FUWCAWvVzykrqmUv1vGv-8og,2026
162
162
  fractal_server/app/schemas/v2/workflowtask.py,sha256=vDdMktYbHeYBgB5OuWSv6wRPRXWqvetkeqQ7IC5YtfA,5751
163
163
  fractal_server/app/security/__init__.py,sha256=8Xd4GxumZgvxEH1Vli3ULehwdesEPiaAbtffJvAEgNo,12509
@@ -178,7 +178,7 @@ fractal_server/migrations/script.py.mako,sha256=oMXw9LC3zRbinWWPPDgeZ4z9FJrV2zhR
178
178
  fractal_server/migrations/versions/034a469ec2eb_task_groups.py,sha256=vrPhC8hfFu1c4HmLHNZyCuqEfecFD8-bWc49bXMNes0,6199
179
179
  fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py,sha256=-BSS9AFTPcu3gYC-sYbawSy4MWQQx8TfMb5BW5EBKmQ,1450
180
180
  fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py,sha256=Q1Gj1cJ0UrdLBJ5AXfFK9QpxTtmcv-4Z3NEGDnxOme4,961
181
- fractal_server/migrations/versions/3082479ac4ea_taskgroup_activity_and_venv_info_to_.py,sha256=oAqSwW9ilKm5x6Wez3JpJFU2-ls2_O8-j1R6KLEir08,3411
181
+ fractal_server/migrations/versions/3082479ac4ea_taskgroup_activity_and_venv_info_to_.py,sha256=_wy9Yu2YfhpBffUsboAG9junlQ2jRR7qui9wbLvXp7w,3653
182
182
  fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py,sha256=-wHe-fOffmYeAm0JXVl_lxZ7hhDkaEVqxgxpHkb_uL8,954
183
183
  fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py,sha256=Mob8McGYAcmgvrseyyYOa54E6Gsgr-4SiGdC-r9O4_A,1157
184
184
  fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py,sha256=5ROUgcoZOdjf8kMt6cxuvPhzHmV6xaCxvZEbhUEyZM4,3271
@@ -202,7 +202,7 @@ fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py
202
202
  fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py,sha256=9BwqUS9Gf7UW_KjrzHbtViC880qhD452KAytkHWWZyk,746
203
203
  fractal_server/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
204
204
  fractal_server/ssh/__init__.py,sha256=sVUmzxf7_DuXG1xoLQ1_00fo5NPhi2LJipSmU5EAkPs,124
205
- fractal_server/ssh/_fabric.py,sha256=udbz8BsbToqf2J_JjSlGUgVQGcP0tY-TjG2plzPoGPM,20180
205
+ fractal_server/ssh/_fabric.py,sha256=Nwsc5uU2BcOE7t1AFFpytKUsZHfbQxB0uKF5HD-dycA,21647
206
206
  fractal_server/string_tools.py,sha256=XtMNsr5R7GmgzmFi68zkKMedHs8vjGoVMMCXqWhIk9k,2568
207
207
  fractal_server/syringe.py,sha256=3qSMW3YaMKKnLdgnooAINOPxnCOxP7y2jeAQYB21Gdo,2786
208
208
  fractal_server/tasks/__init__.py,sha256=kadmVUoIghl8s190_Tt-8f-WBqMi8u8oU4Pvw39NHE8,23
@@ -237,8 +237,8 @@ fractal_server/tasks/v2/utils_templates.py,sha256=C5WLuY3uGG2s53OEL-__H35-fmSlgu
237
237
  fractal_server/urls.py,sha256=5o_qq7PzKKbwq12NHSQZDmDitn5RAOeQ4xufu-2v9Zk,448
238
238
  fractal_server/utils.py,sha256=utvmBx8K9I8hRWFquxna2pBaOqe0JifDL_NVPmihEJI,3525
239
239
  fractal_server/zip_tools.py,sha256=xYpzBshysD2nmxkD5WLYqMzPYUcCRM3kYy-7n9bJL-U,4426
240
- fractal_server-2.9.0a1.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
241
- fractal_server-2.9.0a1.dist-info/METADATA,sha256=VglByOPkGilAORy-ZhR8noitj8xGEBUBLxnJN8EPil0,4585
242
- fractal_server-2.9.0a1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
243
- fractal_server-2.9.0a1.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
244
- fractal_server-2.9.0a1.dist-info/RECORD,,
240
+ fractal_server-2.9.0a2.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
241
+ fractal_server-2.9.0a2.dist-info/METADATA,sha256=Qk7nGzAcl_hZRCJp8pdCV2PQACAWwqOzTCH7nFW__pw,4585
242
+ fractal_server-2.9.0a2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
243
+ fractal_server-2.9.0a2.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
244
+ fractal_server-2.9.0a2.dist-info/RECORD,,