orchestrator-core 4.3.0rc1__py3-none-any.whl → 4.3.0rc3__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.
orchestrator/__init__.py CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  """This is the orchestrator workflow engine."""
15
15
 
16
- __version__ = "4.3.0rc1"
16
+ __version__ = "4.3.0rc3"
17
17
 
18
18
  from orchestrator.app import OrchestratorCore
19
19
  from orchestrator.settings import app_settings
@@ -1,3 +1,4 @@
1
+ from datetime import datetime
1
2
  from typing import Literal
2
3
  from uuid import UUID
3
4
 
@@ -8,7 +9,11 @@ from strawberry.dataloader import DataLoader
8
9
  from orchestrator.db import (
9
10
  SubscriptionTable,
10
11
  )
11
- from orchestrator.services.subscription_relations import get_depends_on_subscriptions, get_in_use_by_subscriptions
12
+ from orchestrator.services.subscription_relations import (
13
+ get_depends_on_subscriptions,
14
+ get_in_use_by_subscriptions,
15
+ get_last_validation_datetimes,
16
+ )
12
17
  from orchestrator.types import SubscriptionLifecycle
13
18
 
14
19
  logger = structlog.get_logger(__name__)
@@ -38,4 +43,10 @@ async def depends_on_subs_loader(keys: list[tuple[UUID, tuple[str, ...]]]) -> li
38
43
  return await get_depends_on_subscriptions(subscription_ids, filter_statuses)
39
44
 
40
45
 
46
+ async def last_validation_datetime_loader(keys: list[UUID]) -> list[datetime | None]:
47
+ """GraphQL dataloader to efficiently get the last validation datetime for multiple subscription_ids."""
48
+ return await get_last_validation_datetimes(keys)
49
+
50
+
41
51
  SubsLoaderType = DataLoader[tuple[UUID, tuple[str, ...]], list[SubscriptionTable]]
52
+ LastValidationLoaderType = DataLoader[UUID, datetime | None]
@@ -175,6 +175,10 @@ class SubscriptionInterface:
175
175
  ]
176
176
  return await resolve_subscriptions(info, filter_by_with_related_subscriptions, sort_by, first, after)
177
177
 
178
+ @strawberry.field(description="Returns the date and time of the last validation workflow run for a subscription") # type: ignore
179
+ async def last_validated_at(self, info: OrchestratorInfo) -> datetime | None:
180
+ return await info.context.core_last_validation_datetime_loader.load(self.subscription_id)
181
+
178
182
  @strawberry.field(description="Returns customer of a subscription") # type: ignore
179
183
  def customer(self) -> CustomerType:
180
184
  return CustomerType(
@@ -30,7 +30,13 @@ from oauth2_lib.fastapi import AuthManager
30
30
  from oauth2_lib.strawberry import OauthContext
31
31
  from orchestrator.db.filters import Filter
32
32
  from orchestrator.db.sorting import Sort, SortOrder
33
- from orchestrator.graphql.loaders.subscriptions import SubsLoaderType, depends_on_subs_loader, in_use_by_subs_loader
33
+ from orchestrator.graphql.loaders.subscriptions import (
34
+ LastValidationLoaderType,
35
+ SubsLoaderType,
36
+ depends_on_subs_loader,
37
+ in_use_by_subs_loader,
38
+ last_validation_datetime_loader,
39
+ )
34
40
  from orchestrator.services.process_broadcast_thread import ProcessDataBroadcastThread
35
41
 
36
42
  StrawberryPydanticModel = TypeVar("StrawberryPydanticModel", bound=StrawberryTypeFromPydantic)
@@ -60,6 +66,9 @@ class OrchestratorContext(OauthContext):
60
66
  self.graphql_models = graphql_models or {}
61
67
  self.core_in_use_by_subs_loader: SubsLoaderType = DataLoader(load_fn=in_use_by_subs_loader)
62
68
  self.core_depends_on_subs_loader: SubsLoaderType = DataLoader(load_fn=depends_on_subs_loader)
69
+ self.core_last_validation_datetime_loader: LastValidationLoaderType = DataLoader(
70
+ load_fn=last_validation_datetime_loader
71
+ )
63
72
  super().__init__(auth_manager)
64
73
 
65
74
 
File without changes
@@ -41,7 +41,7 @@ def retrieve_input_state(process_id: UUID, input_type: InputType, raise_exceptio
41
41
  select(InputStateTable)
42
42
  .filter(InputStateTable.process_id == process_id)
43
43
  .filter(InputStateTable.input_type == input_type)
44
- .order_by(InputStateTable.input_time.asc())
44
+ .order_by(InputStateTable.input_time.desc())
45
45
  ).first()
46
46
 
47
47
  if res:
@@ -1,15 +1,18 @@
1
+ from datetime import datetime
1
2
  from itertools import chain
2
3
  from typing import Any, Awaitable, Callable, NamedTuple
3
4
  from uuid import UUID
4
5
 
5
6
  import structlog
6
7
  from more_itertools import flatten, unique_everseen
7
- from sqlalchemy import Row, select
8
+ from sqlalchemy import Row, func, select
8
9
  from sqlalchemy import Text as SaText
9
10
  from sqlalchemy import cast as sa_cast
10
11
  from sqlalchemy.orm import aliased
11
12
 
12
13
  from orchestrator.db import (
14
+ ProcessSubscriptionTable,
15
+ ProcessTable,
13
16
  ResourceTypeTable,
14
17
  SubscriptionInstanceTable,
15
18
  SubscriptionInstanceValueTable,
@@ -267,3 +270,20 @@ async def get_recursive_relations(
267
270
  relation_fetcher=relation_fetcher,
268
271
  )
269
272
  return list(unique_everseen(relations + nested_relations, key=lambda s: s.subscription_id))
273
+
274
+
275
+ async def get_last_validation_datetimes(subscription_ids: list[UUID]) -> list[datetime | None]:
276
+ stmt = (
277
+ select(ProcessSubscriptionTable.subscription_id, func.max(ProcessTable.last_modified_at))
278
+ .join(ProcessSubscriptionTable)
279
+ .group_by(ProcessSubscriptionTable.subscription_id)
280
+ .where(
281
+ (ProcessSubscriptionTable.workflow_target == "VALIDATE")
282
+ & ProcessSubscriptionTable.subscription_id.in_(subscription_ids)
283
+ )
284
+ )
285
+ results = db.session.execute(stmt).all()
286
+ last_validation_indexed_by_sub_id = {
287
+ str(subscription_id): last_validation for subscription_id, last_validation in results
288
+ }
289
+ return [last_validation_indexed_by_sub_id.get(str(subscription_id), None) for subscription_id in subscription_ids]
@@ -72,7 +72,7 @@ def initialise_celery(celery: Celery) -> None: # noqa: C901
72
72
  process = _get_process(process_id)
73
73
  pstat = load_process(process)
74
74
  ensure_correct_process_status(process_id, ProcessStatus.CREATED)
75
- thread_start_process(pstat, user)
75
+ thread_start_process(pstat, user=user, broadcast_func=process_broadcast_fn)
76
76
 
77
77
  except Exception as exc:
78
78
  local_logger.error("Worker failed to execute workflow", process_id=process_id, details=str(exc))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orchestrator-core
3
- Version: 4.3.0rc1
3
+ Version: 4.3.0rc3
4
4
  Summary: This is the orchestrator workflow engine.
5
5
  Author-email: SURF <automation-beheer@surf.nl>
6
6
  Requires-Python: >=3.11,<3.14
@@ -1,4 +1,4 @@
1
- orchestrator/__init__.py,sha256=AwwISw88tXUMDIxHF1Kl8PnfRUj8xQIIe6WpuvTlxw4,1066
1
+ orchestrator/__init__.py,sha256=lbvy3YdyWB-J3dJ8Xjo9-oPvJJ1Pk-TrnAVSkzbCDy4,1066
2
2
  orchestrator/app.py,sha256=7UrXKjBKNSEaSSXAd5ww_RdMFhFqE4yvfj8faS2MzAA,12089
3
3
  orchestrator/exception_handlers.py,sha256=UsW3dw8q0QQlNLcV359bIotah8DYjMsj2Ts1LfX4ClY,1268
4
4
  orchestrator/log_config.py,sha256=1tPRX5q65e57a6a_zEii_PFK8SzWT0mnA5w2sKg4hh8,1853
@@ -159,12 +159,12 @@ orchestrator/graphql/__init__.py,sha256=avq8Yg3Jr_9pJqh7ClyIAOX7YSg1eM_AWmt5C3FR
159
159
  orchestrator/graphql/autoregistration.py,sha256=pF2jbMKG26MvYoMSa6ZpqpHjVks7_NvSRFymHTgmfjs,6342
160
160
  orchestrator/graphql/pagination.py,sha256=iqVDn3GPZpiQhEydfwkBJLURY-X8wwUphS8Lkeg0BOc,2413
161
161
  orchestrator/graphql/schema.py,sha256=gwZ3nAgKL0zlpc-aK58hSUAGPVD11Tb3aRSSK9hC39I,9204
162
- orchestrator/graphql/types.py,sha256=CpWrDqVTQwxYkJQqidPzHEAURGirJ-6i-dlBcBwBaTI,5196
162
+ orchestrator/graphql/types.py,sha256=_kHKMusrRPuRtF4wm42NsBzoFZ4egbu3ibMmhd2D6Fs,5432
163
163
  orchestrator/graphql/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
164
164
  orchestrator/graphql/extensions/model_cache.py,sha256=1uhMRjBs9eK7zJ1Y6P6BopX06822w2Yh9jliwYvG6yQ,1085
165
165
  orchestrator/graphql/extensions/stats.py,sha256=pGhEBQg45XvqZhRobcrCSGwt5AGmR3gflsm1dYiIg5g,2018
166
166
  orchestrator/graphql/loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
167
- orchestrator/graphql/loaders/subscriptions.py,sha256=31zE2WC7z-tPIUmVpU1QWOJvNbLvF7sYgY7JAQ6OPJg,1856
167
+ orchestrator/graphql/loaders/subscriptions.py,sha256=0deS91hn95CX1KY4NAKgYSfVBqioSc-Q3sdOrTJTaDc,2244
168
168
  orchestrator/graphql/mutations/customer_description.py,sha256=zm_X1yvWl4qC97_rYUYSF-1q1gFrQX6fDrzQKhguDYs,3359
169
169
  orchestrator/graphql/mutations/start_process.py,sha256=8vLVvmBwL1ujbZJoI_8YE3VAgI-J2RTzgrTZJC8THZ4,1576
170
170
  orchestrator/graphql/resolvers/__init__.py,sha256=EEw9NO4LAryfrpkLlgsNQ9rytKd0usBDx95OURRV6sg,1031
@@ -190,7 +190,7 @@ orchestrator/graphql/schemas/product_block.py,sha256=Qk9cbA6vm7ZPrhdgPHatKRuy6Ty
190
190
  orchestrator/graphql/schemas/resource_type.py,sha256=s5d_FwQXL2-Sc-IDUxTJun5qFQ4zOP4-XcHF9ql-t1g,898
191
191
  orchestrator/graphql/schemas/settings.py,sha256=drhm5VcLmUbiYAk6WUSJcyJqjNM96E6GvpxVdPAobnA,999
192
192
  orchestrator/graphql/schemas/strawberry_pydantic_patch.py,sha256=CjNUhTKdYmLiaem-WY_mzw4HASIeaZitxGF8pPocqVw,1602
193
- orchestrator/graphql/schemas/subscription.py,sha256=RnnxPgha_7D4Ii87cp3eyBV93_RZIryzWyVHZwyn3eA,9603
193
+ orchestrator/graphql/schemas/subscription.py,sha256=hTA34C27kgLguH9V53173CxMKIWiQKh3vFzyJ2yBfE0,9918
194
194
  orchestrator/graphql/schemas/version.py,sha256=HSzVg_y4Sjd5_H5rRUtu3FJKOG_8ifhvBNt_qjOtC-E,92
195
195
  orchestrator/graphql/schemas/workflow.py,sha256=WLbegRNxOfvXg4kPYrO5KPBwtHmUofAr2pvZT2JsW1c,1761
196
196
  orchestrator/graphql/utils/__init__.py,sha256=1JvenzEVW1CBa1sGVI9I8IWnnoXIkb1hneDqph9EEZY,524
@@ -208,6 +208,7 @@ orchestrator/metrics/init.py,sha256=xBITvDjbNf-iabbBg0tAW8TPj6-wzr_MerOOqgDsoS4,
208
208
  orchestrator/metrics/processes.py,sha256=SyogN5NSuhYoRv2CSUE1So9e8Gkrwa71J6oGLOdODQU,5333
209
209
  orchestrator/metrics/subscriptions.py,sha256=vC1O8VmTq5oJxNrn5CU99Rf8cxzdyhc7tXbZBSAU-O8,3036
210
210
  orchestrator/migrations/README,sha256=heMzebYwlGhnE8_4CWJ4LS74WoEZjBy-S-mIJRxAEKI,39
211
+ orchestrator/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
211
212
  orchestrator/migrations/alembic.ini,sha256=kMoADqhGeubU8xanILNaqm4oixLy9m4ngYtdGpZcc7I,873
212
213
  orchestrator/migrations/env.py,sha256=M_cPoAL2axuuup5fvMy8I_WTPHEw0RbPEHkhZ3QEGoE,3740
213
214
  orchestrator/migrations/helpers.py,sha256=CAGGKhxpmhyKGfYcO-SUCPfMTOCZPfEpkJrcm2MYfcE,47979
@@ -264,16 +265,16 @@ orchestrator/schemas/subscription_descriptions.py,sha256=Ft_jw1U0bf9Z0U8O4OWfLlc
264
265
  orchestrator/schemas/workflow.py,sha256=VqQ9XfV4fVd6MjY0LRRQzWBJHmlPsAamWfTwDx1cZkg,2102
265
266
  orchestrator/services/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
266
267
  orchestrator/services/fixed_inputs.py,sha256=kyz7s2HLzyDulvcq-ZqefTw1om86COvyvTjz0_5CmgI,876
267
- orchestrator/services/input_state.py,sha256=WfiQrvatPtE1jR8xArE0XamONt1nemTv5iaROgSiJpM,2389
268
+ orchestrator/services/input_state.py,sha256=6BZOpb3cHpO18K-XG-3QUIV9pIM25_ufdODrp5CmXG4,2390
268
269
  orchestrator/services/process_broadcast_thread.py,sha256=D44YbjF8mRqGuznkRUV4SoRn1J0lfy_x1H508GnSVlU,4649
269
270
  orchestrator/services/processes.py,sha256=JGM9vWbUjvEpy-IpTIgaYaqcTBKMI-CWTY8SJKBf3eI,30153
270
271
  orchestrator/services/products.py,sha256=BP4KyE8zO-8z7Trrs5T6zKBOw53S9BfBJnHWI3p6u5Y,1943
271
272
  orchestrator/services/resource_types.py,sha256=_QBy_JOW_X3aSTqH0CuLrq4zBJL0p7Q-UDJUcuK2_qc,884
272
273
  orchestrator/services/settings.py,sha256=HEWfFulgoEDwgfxGEO__QTr5fDiwNBEj1UhAeTAdbLQ,3159
273
274
  orchestrator/services/settings_env_variables.py,sha256=iPErQjqPQCxKs0sPhefB16d8SBBVUi6eiRnFBK5bgqA,2196
274
- orchestrator/services/subscription_relations.py,sha256=9C126TUfFvyBe7y4x007kH_dvxJ9pZ1zSnaWeH6HC5k,12261
275
+ orchestrator/services/subscription_relations.py,sha256=aIdyzwyyy58OFhwjRPCPgnQTUTmChu6SeSQRIleQoDE,13138
275
276
  orchestrator/services/subscriptions.py,sha256=nr2HI89nC0lYjzTh2j-lEQ5cPQK43LNZv3gvP6jbepw,27189
276
- orchestrator/services/tasks.py,sha256=Mq-C7EDrkv-ohhzD9H03Oh540heL19dxvyauHi_0pNI,5246
277
+ orchestrator/services/tasks.py,sha256=mR3Fj1VsudltpanJKI2PvrxersyhVQ1skp8H7r3XnYI,5288
277
278
  orchestrator/services/translations.py,sha256=GyP8soUFGej8AS8uulBsk10CCK6Kwfjv9AHMFm3ElQY,1713
278
279
  orchestrator/services/workflows.py,sha256=iEkt2OBuTwkDru4V6ZSKatnw0b96ZdPV-VQqeZ9EOgU,4015
279
280
  orchestrator/services/executors/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
@@ -315,7 +316,7 @@ orchestrator/workflows/tasks/resume_workflows.py,sha256=T3iobSJjVgiupe0rClD34kUZ
315
316
  orchestrator/workflows/tasks/validate_product_type.py,sha256=paG-NAY1bdde3Adt8zItkcBKf5Pxw6f5ngGW6an6dYU,3192
316
317
  orchestrator/workflows/tasks/validate_products.py,sha256=GZJBoFF-WMphS7ghMs2-gqvV2iL1F0POhk0uSNt93n0,8510
317
318
  orchestrator/workflows/translations/en-GB.json,sha256=ST53HxkphFLTMjFHonykDBOZ7-P_KxksktZU3GbxLt0,846
318
- orchestrator_core-4.3.0rc1.dist-info/licenses/LICENSE,sha256=b-aA5OZQuuBATmLKo_mln8CQrDPPhg3ghLzjPjLn4Tg,11409
319
- orchestrator_core-4.3.0rc1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
320
- orchestrator_core-4.3.0rc1.dist-info/METADATA,sha256=LjswuvIeH5R2RgHE84Fr0MhOMfg9lo9g_F9YtTcyjbE,5963
321
- orchestrator_core-4.3.0rc1.dist-info/RECORD,,
319
+ orchestrator_core-4.3.0rc3.dist-info/licenses/LICENSE,sha256=b-aA5OZQuuBATmLKo_mln8CQrDPPhg3ghLzjPjLn4Tg,11409
320
+ orchestrator_core-4.3.0rc3.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
321
+ orchestrator_core-4.3.0rc3.dist-info/METADATA,sha256=IJC4njtGAr5-C01qYF38rwvOkhXCCX7uwYZ4-ej1vz0,5963
322
+ orchestrator_core-4.3.0rc3.dist-info/RECORD,,