orchestrator-core 4.3.0rc1__py3-none-any.whl → 4.3.0rc2__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.0rc2"
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
 
@@ -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.0rc2
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=k7E0AiB5QFgGg_GlFGkYHF-DTfhWCYkziVwvIXSWeAc,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
@@ -271,9 +271,9 @@ orchestrator/services/products.py,sha256=BP4KyE8zO-8z7Trrs5T6zKBOw53S9BfBJnHWI3p
271
271
  orchestrator/services/resource_types.py,sha256=_QBy_JOW_X3aSTqH0CuLrq4zBJL0p7Q-UDJUcuK2_qc,884
272
272
  orchestrator/services/settings.py,sha256=HEWfFulgoEDwgfxGEO__QTr5fDiwNBEj1UhAeTAdbLQ,3159
273
273
  orchestrator/services/settings_env_variables.py,sha256=iPErQjqPQCxKs0sPhefB16d8SBBVUi6eiRnFBK5bgqA,2196
274
- orchestrator/services/subscription_relations.py,sha256=9C126TUfFvyBe7y4x007kH_dvxJ9pZ1zSnaWeH6HC5k,12261
274
+ orchestrator/services/subscription_relations.py,sha256=aIdyzwyyy58OFhwjRPCPgnQTUTmChu6SeSQRIleQoDE,13138
275
275
  orchestrator/services/subscriptions.py,sha256=nr2HI89nC0lYjzTh2j-lEQ5cPQK43LNZv3gvP6jbepw,27189
276
- orchestrator/services/tasks.py,sha256=Mq-C7EDrkv-ohhzD9H03Oh540heL19dxvyauHi_0pNI,5246
276
+ orchestrator/services/tasks.py,sha256=mR3Fj1VsudltpanJKI2PvrxersyhVQ1skp8H7r3XnYI,5288
277
277
  orchestrator/services/translations.py,sha256=GyP8soUFGej8AS8uulBsk10CCK6Kwfjv9AHMFm3ElQY,1713
278
278
  orchestrator/services/workflows.py,sha256=iEkt2OBuTwkDru4V6ZSKatnw0b96ZdPV-VQqeZ9EOgU,4015
279
279
  orchestrator/services/executors/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
@@ -315,7 +315,7 @@ orchestrator/workflows/tasks/resume_workflows.py,sha256=T3iobSJjVgiupe0rClD34kUZ
315
315
  orchestrator/workflows/tasks/validate_product_type.py,sha256=paG-NAY1bdde3Adt8zItkcBKf5Pxw6f5ngGW6an6dYU,3192
316
316
  orchestrator/workflows/tasks/validate_products.py,sha256=GZJBoFF-WMphS7ghMs2-gqvV2iL1F0POhk0uSNt93n0,8510
317
317
  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,,
318
+ orchestrator_core-4.3.0rc2.dist-info/licenses/LICENSE,sha256=b-aA5OZQuuBATmLKo_mln8CQrDPPhg3ghLzjPjLn4Tg,11409
319
+ orchestrator_core-4.3.0rc2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
320
+ orchestrator_core-4.3.0rc2.dist-info/METADATA,sha256=aJsbvoK-FPIjx_tH3UJy3KWgj6aLhFwUb7tJvUxq9gQ,5963
321
+ orchestrator_core-4.3.0rc2.dist-info/RECORD,,