orchestrator-core 3.2.3__py3-none-any.whl → 4.0.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 +1 -1
- orchestrator/api/api_v1/endpoints/subscription_customer_descriptions.py +0 -2
- orchestrator/cli/generator/templates/new_product_migration.j2 +5 -1
- orchestrator/cli/migrate_tasks.py +5 -5
- orchestrator/cli/migrate_workflows.py +1 -2
- orchestrator/db/models.py +3 -1
- orchestrator/domain/base.py +4 -24
- orchestrator/domain/customer_description.py +0 -4
- orchestrator/graphql/mutations/customer_description.py +1 -1
- orchestrator/migrations/helpers.py +14 -6
- orchestrator/migrations/versions/schema/2025-02-20_68d14db1b8da_make_workflow_description_mandatory.py +33 -0
- orchestrator/migrations/versions/schema/2025-05-08_161918133bec_add_is_task_to_workflow.py +28 -0
- orchestrator/schedules/validate_subscriptions.py +4 -4
- orchestrator/schemas/workflow.py +1 -0
- orchestrator/services/celery.py +11 -3
- orchestrator/services/processes.py +2 -2
- orchestrator/services/subscriptions.py +10 -23
- orchestrator/services/workflows.py +8 -4
- orchestrator/settings.py +0 -4
- orchestrator/targets.py +1 -0
- orchestrator/utils/get_subscription_dict.py +0 -4
- orchestrator/utils/redis.py +1 -67
- orchestrator/workflows/modify_note.py +3 -11
- orchestrator/workflows/steps.py +2 -86
- orchestrator/workflows/tasks/validate_product_type.py +2 -2
- orchestrator/workflows/tasks/validate_products.py +3 -6
- orchestrator/workflows/utils.py +3 -23
- {orchestrator_core-3.2.3.dist-info → orchestrator_core-4.0.0rc2.dist-info}/METADATA +6 -6
- {orchestrator_core-3.2.3.dist-info → orchestrator_core-4.0.0rc2.dist-info}/RECORD +31 -29
- {orchestrator_core-3.2.3.dist-info → orchestrator_core-4.0.0rc2.dist-info}/WHEEL +0 -0
- {orchestrator_core-3.2.3.dist-info → orchestrator_core-4.0.0rc2.dist-info}/licenses/LICENSE +0 -0
orchestrator/__init__.py
CHANGED
|
@@ -28,7 +28,6 @@ from orchestrator.domain.customer_description import (
|
|
|
28
28
|
from orchestrator.schemas import SubscriptionDescriptionBaseSchema, SubscriptionDescriptionSchema
|
|
29
29
|
from orchestrator.schemas.subscription_descriptions import UpdateSubscriptionDescriptionSchema
|
|
30
30
|
from orchestrator.utils.errors import StaleDataError
|
|
31
|
-
from orchestrator.utils.redis import delete_from_redis
|
|
32
31
|
|
|
33
32
|
router = APIRouter()
|
|
34
33
|
|
|
@@ -55,7 +54,6 @@ def delete_subscription_customer_descriptions(_id: UUID) -> None:
|
|
|
55
54
|
description = db.session.get(SubscriptionCustomerDescriptionTable, _id)
|
|
56
55
|
if description:
|
|
57
56
|
delete(SubscriptionCustomerDescriptionTable, _id)
|
|
58
|
-
delete_from_redis(description.subscription_id)
|
|
59
57
|
|
|
60
58
|
|
|
61
59
|
@router.get("/{_id}", response_model=SubscriptionDescriptionSchema)
|
|
@@ -63,24 +63,28 @@ new_workflows = [
|
|
|
63
63
|
{
|
|
64
64
|
"name": "create_{{ product.variable }}",
|
|
65
65
|
"target": Target.CREATE,
|
|
66
|
+
"is_task": False,
|
|
66
67
|
"description": "Create {{ product.name }}",
|
|
67
68
|
"product_type": "{{ product.type }}",
|
|
68
69
|
},
|
|
69
70
|
{
|
|
70
71
|
"name": "modify_{{ product.variable }}",
|
|
71
72
|
"target": Target.MODIFY,
|
|
73
|
+
"is_task": False,
|
|
72
74
|
"description": "Modify {{ product.name }}",
|
|
73
75
|
"product_type": "{{ product.type }}",
|
|
74
76
|
},
|
|
75
77
|
{
|
|
76
78
|
"name": "terminate_{{ product.variable }}",
|
|
77
79
|
"target": Target.TERMINATE,
|
|
80
|
+
"is_task": False,
|
|
78
81
|
"description": "Terminate {{ product.name }}",
|
|
79
82
|
"product_type": "{{ product.type }}",
|
|
80
83
|
},
|
|
81
84
|
{
|
|
82
85
|
"name": "validate_{{ product.variable }}",
|
|
83
|
-
"target": Target.
|
|
86
|
+
"target": Target.VALIDATE,
|
|
87
|
+
"is_task": True,
|
|
84
88
|
"description": "Validate {{ product.name }}",
|
|
85
89
|
"product_type": "{{ product.type }}",
|
|
86
90
|
},
|
|
@@ -150,22 +150,22 @@ def create_tasks_migration_wizard() -> tuple[list[dict], list[dict]]:
|
|
|
150
150
|
- list of task items to add in the migration
|
|
151
151
|
- list of task items to delete in the migration
|
|
152
152
|
"""
|
|
153
|
-
database_tasks = {
|
|
154
|
-
task.name: task for task in list(db.session.scalars(select(WorkflowTable))) if task.target == Target.SYSTEM
|
|
155
|
-
}
|
|
153
|
+
database_tasks = {task.name: task for task in list(db.session.scalars(select(WorkflowTable))) if task.is_task}
|
|
156
154
|
registered_wf_instances = {
|
|
157
155
|
task: cast(Workflow, get_workflow(task)) for task in orchestrator.workflows.ALL_WORKFLOWS.keys()
|
|
158
156
|
}
|
|
159
157
|
|
|
158
|
+
is_task = [Target.SYSTEM, Target.VALIDATE]
|
|
159
|
+
|
|
160
160
|
registered_tasks = dict(
|
|
161
161
|
filter(
|
|
162
|
-
lambda task: task[1].target
|
|
162
|
+
lambda task: task[1].target in is_task and task[0] in database_tasks.keys(),
|
|
163
163
|
registered_wf_instances.items(),
|
|
164
164
|
)
|
|
165
165
|
)
|
|
166
166
|
available_tasks = dict(
|
|
167
167
|
filter(
|
|
168
|
-
lambda task: task[1].target
|
|
168
|
+
lambda task: task[1].target in is_task and task[0] not in database_tasks.keys(),
|
|
169
169
|
registered_wf_instances.items(),
|
|
170
170
|
)
|
|
171
171
|
)
|
|
@@ -11,7 +11,6 @@ import orchestrator.workflows
|
|
|
11
11
|
from orchestrator.cli.helpers.input_helpers import _enumerate_menu_keys, _prompt_user_menu, get_user_input
|
|
12
12
|
from orchestrator.cli.helpers.print_helpers import COLOR, noqa_print, print_fmt, str_fmt
|
|
13
13
|
from orchestrator.db import ProductTable, WorkflowTable, db
|
|
14
|
-
from orchestrator.targets import Target
|
|
15
14
|
from orchestrator.workflows import LazyWorkflowInstance, get_workflow
|
|
16
15
|
|
|
17
16
|
# Workflows are registered via migrations with product type. For every product with the given product_type, there will be an entry in products_workflows.
|
|
@@ -183,7 +182,7 @@ def create_workflows_migration_wizard() -> tuple[list[dict], list[dict]]:
|
|
|
183
182
|
"""
|
|
184
183
|
database_workflows = list(db.session.scalars(select(WorkflowTable)))
|
|
185
184
|
registered_workflows = orchestrator.workflows.ALL_WORKFLOWS
|
|
186
|
-
system_workflow_names = {wf.name for wf in database_workflows if wf.
|
|
185
|
+
system_workflow_names = {wf.name for wf in database_workflows if wf.is_task}
|
|
187
186
|
registered_non_system_workflows = {k: v for k, v in registered_workflows.items() if k not in system_workflow_names}
|
|
188
187
|
|
|
189
188
|
unregistered_workflows = [wf for wf in database_workflows if wf.name not in registered_workflows.keys()]
|
orchestrator/db/models.py
CHANGED
|
@@ -400,7 +400,7 @@ class WorkflowTable(BaseModel):
|
|
|
400
400
|
workflow_id = mapped_column(UUIDType, server_default=text("uuid_generate_v4()"), primary_key=True)
|
|
401
401
|
name = mapped_column(String(), nullable=False, unique=True)
|
|
402
402
|
target = mapped_column(String(), nullable=False)
|
|
403
|
-
description = mapped_column(Text(), nullable=
|
|
403
|
+
description = mapped_column(Text(), nullable=False)
|
|
404
404
|
created_at = mapped_column(UtcTimestamp, nullable=False, server_default=text("current_timestamp()"))
|
|
405
405
|
deleted_at = mapped_column(UtcTimestamp, deferred=True)
|
|
406
406
|
|
|
@@ -412,6 +412,8 @@ class WorkflowTable(BaseModel):
|
|
|
412
412
|
)
|
|
413
413
|
processes = relationship("ProcessTable", cascade="all, delete-orphan", back_populates="workflow")
|
|
414
414
|
|
|
415
|
+
is_task = mapped_column(Boolean, nullable=False, server_default=text("false"))
|
|
416
|
+
|
|
415
417
|
@staticmethod
|
|
416
418
|
def select() -> Select:
|
|
417
419
|
return (
|
orchestrator/domain/base.py
CHANGED
|
@@ -1294,27 +1294,13 @@ class SubscriptionModel(DomainModel):
|
|
|
1294
1294
|
# Some common functions shared by from_other_product and from_subscription
|
|
1295
1295
|
@classmethod
|
|
1296
1296
|
def _get_subscription(cls: type[S], subscription_id: UUID | UUIDstr) -> SubscriptionTable | None:
|
|
1297
|
-
from orchestrator.settings import app_settings
|
|
1298
1297
|
|
|
1299
1298
|
if not isinstance(subscription_id, UUID | UUIDstr):
|
|
1300
1299
|
raise TypeError(f"subscription_id is of type {type(subscription_id)} instead of UUID | UUIDstr")
|
|
1301
1300
|
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
joinedload(SubscriptionTable.product).selectinload(ProductTable.fixed_inputs),
|
|
1306
|
-
]
|
|
1307
|
-
|
|
1308
|
-
else:
|
|
1309
|
-
loaders = [
|
|
1310
|
-
selectinload(SubscriptionTable.instances)
|
|
1311
|
-
.joinedload(SubscriptionInstanceTable.product_block)
|
|
1312
|
-
.selectinload(ProductBlockTable.resource_types),
|
|
1313
|
-
selectinload(SubscriptionTable.instances).selectinload(
|
|
1314
|
-
SubscriptionInstanceTable.in_use_by_block_relations
|
|
1315
|
-
),
|
|
1316
|
-
selectinload(SubscriptionTable.instances).selectinload(SubscriptionInstanceTable.values),
|
|
1317
|
-
]
|
|
1301
|
+
loaders = [
|
|
1302
|
+
joinedload(SubscriptionTable.product).selectinload(ProductTable.fixed_inputs),
|
|
1303
|
+
]
|
|
1318
1304
|
|
|
1319
1305
|
return db.session.get(SubscriptionTable, subscription_id, options=loaders)
|
|
1320
1306
|
|
|
@@ -1394,7 +1380,6 @@ class SubscriptionModel(DomainModel):
|
|
|
1394
1380
|
def from_subscription(cls: type[S], subscription_id: UUID | UUIDstr) -> S:
|
|
1395
1381
|
"""Use a subscription_id to return required fields of an existing subscription."""
|
|
1396
1382
|
from orchestrator.domain.context_cache import get_from_cache, store_in_cache
|
|
1397
|
-
from orchestrator.settings import app_settings
|
|
1398
1383
|
|
|
1399
1384
|
if cached_model := get_from_cache(subscription_id):
|
|
1400
1385
|
return cast(S, cached_model)
|
|
@@ -1421,12 +1406,7 @@ class SubscriptionModel(DomainModel):
|
|
|
1421
1406
|
|
|
1422
1407
|
fixed_inputs = {fi.name: fi.value for fi in subscription.product.fixed_inputs}
|
|
1423
1408
|
|
|
1424
|
-
instances
|
|
1425
|
-
if app_settings.ENABLE_SUBSCRIPTION_MODEL_OPTIMIZATIONS:
|
|
1426
|
-
# TODO #900 remove toggle and make this path the default
|
|
1427
|
-
instances = cls._load_root_instances(subscription_id)
|
|
1428
|
-
else:
|
|
1429
|
-
instances = cls._load_instances(subscription.instances, status, match_domain_attr=False)
|
|
1409
|
+
instances = cls._load_root_instances(subscription_id)
|
|
1430
1410
|
|
|
1431
1411
|
try:
|
|
1432
1412
|
model = cls(
|
|
@@ -21,7 +21,6 @@ from sqlalchemy import select
|
|
|
21
21
|
from orchestrator.api.models import delete
|
|
22
22
|
from orchestrator.db import SubscriptionCustomerDescriptionTable, db
|
|
23
23
|
from orchestrator.utils.errors import StaleDataError
|
|
24
|
-
from orchestrator.utils.redis import delete_subscription_from_redis
|
|
25
24
|
from orchestrator.utils.validate_data_version import validate_data_version
|
|
26
25
|
from orchestrator.websocket import invalidate_subscription_cache
|
|
27
26
|
|
|
@@ -38,7 +37,6 @@ def get_customer_description_by_customer_subscription(
|
|
|
38
37
|
return db.session.scalars(stmt).one_or_none()
|
|
39
38
|
|
|
40
39
|
|
|
41
|
-
@delete_subscription_from_redis()
|
|
42
40
|
async def create_subscription_customer_description(
|
|
43
41
|
customer_id: str, subscription_id: UUID, description: str
|
|
44
42
|
) -> SubscriptionCustomerDescriptionTable:
|
|
@@ -53,7 +51,6 @@ async def create_subscription_customer_description(
|
|
|
53
51
|
return customer_description
|
|
54
52
|
|
|
55
53
|
|
|
56
|
-
@delete_subscription_from_redis()
|
|
57
54
|
async def update_subscription_customer_description(
|
|
58
55
|
customer_description: SubscriptionCustomerDescriptionTable,
|
|
59
56
|
description: str,
|
|
@@ -70,7 +67,6 @@ async def update_subscription_customer_description(
|
|
|
70
67
|
return customer_description
|
|
71
68
|
|
|
72
69
|
|
|
73
|
-
@delete_subscription_from_redis()
|
|
74
70
|
async def delete_subscription_customer_description_by_customer_subscription(
|
|
75
71
|
customer_id: str, subscription_id: UUID
|
|
76
72
|
) -> SubscriptionCustomerDescriptionTable | None:
|
|
@@ -60,7 +60,7 @@ async def resolve_remove_customer_description(
|
|
|
60
60
|
)
|
|
61
61
|
if not description:
|
|
62
62
|
return NotFoundError(message="Customer description not found")
|
|
63
|
-
return CustomerDescription.from_pydantic(description)
|
|
63
|
+
return CustomerDescription.from_pydantic(description) # type: ignore
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
@strawberry.type(description="Customer subscription description mutations")
|
|
@@ -135,18 +135,21 @@ def create_workflow(conn: sa.engine.Connection, workflow: dict) -> None:
|
|
|
135
135
|
>>> workflow = {
|
|
136
136
|
"name": "workflow_name",
|
|
137
137
|
"target": "SYSTEM",
|
|
138
|
+
"is_task": False,
|
|
138
139
|
"description": "workflow description",
|
|
139
140
|
"product_type": "product_type",
|
|
140
141
|
}
|
|
141
142
|
>>> create_workflow(conn, workflow)
|
|
142
143
|
"""
|
|
144
|
+
if not workflow.get("is_task", False):
|
|
145
|
+
workflow["is_task"] = False
|
|
143
146
|
|
|
144
147
|
conn.execute(
|
|
145
148
|
sa.text(
|
|
146
149
|
"""
|
|
147
150
|
WITH new_workflow AS (
|
|
148
|
-
INSERT INTO workflows(name, target, description)
|
|
149
|
-
VALUES (:name, :target, :description)
|
|
151
|
+
INSERT INTO workflows(name, target, is_task, description)
|
|
152
|
+
VALUES (:name, :target, :is_task, :description)
|
|
150
153
|
ON CONFLICT DO NOTHING
|
|
151
154
|
RETURNING workflow_id)
|
|
152
155
|
INSERT
|
|
@@ -184,8 +187,8 @@ def create_task(conn: sa.engine.Connection, task: dict) -> None:
|
|
|
184
187
|
conn.execute(
|
|
185
188
|
sa.text(
|
|
186
189
|
"""
|
|
187
|
-
INSERT INTO workflows(name, target, description)
|
|
188
|
-
VALUES (:name, 'SYSTEM', :description)
|
|
190
|
+
INSERT INTO workflows(name, target, is_task, description)
|
|
191
|
+
VALUES (:name, 'SYSTEM', TRUE, :description)
|
|
189
192
|
ON CONFLICT DO NOTHING
|
|
190
193
|
RETURNING workflow_id
|
|
191
194
|
"""
|
|
@@ -206,6 +209,7 @@ def create_workflows(conn: sa.engine.Connection, new: dict) -> None:
|
|
|
206
209
|
"workflow_name": {
|
|
207
210
|
"workflow_id": "f2702074-3203-454c-b298-6dfa7675423d",
|
|
208
211
|
"target": "CREATE",
|
|
212
|
+
"is_task": False,
|
|
209
213
|
"description": "Workflow description",
|
|
210
214
|
"tag": "ProductBlockName1",
|
|
211
215
|
"search_phrase": "Search Phrase%",
|
|
@@ -214,12 +218,16 @@ def create_workflows(conn: sa.engine.Connection, new: dict) -> None:
|
|
|
214
218
|
"""
|
|
215
219
|
for name, workflow in new.items():
|
|
216
220
|
workflow["name"] = name
|
|
221
|
+
|
|
222
|
+
if not workflow.get("is_task", False):
|
|
223
|
+
workflow["is_task"] = False
|
|
224
|
+
|
|
217
225
|
conn.execute(
|
|
218
226
|
sa.text(
|
|
219
227
|
"""
|
|
220
228
|
WITH new_workflow AS (
|
|
221
|
-
INSERT INTO workflows(workflow_id, name, target, description)
|
|
222
|
-
VALUES (:workflow_id, :name, :target, :description)
|
|
229
|
+
INSERT INTO workflows(workflow_id, name, target, is_task, description)
|
|
230
|
+
VALUES (:workflow_id, :name, :target, :is_task, :description)
|
|
223
231
|
RETURNING workflow_id)
|
|
224
232
|
INSERT
|
|
225
233
|
INTO products_workflows (product_id, workflow_id)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Make workflow description mandatory.
|
|
2
|
+
|
|
3
|
+
Revision ID: 68d14db1b8da
|
|
4
|
+
Revises: bac6be6f2b4f
|
|
5
|
+
Create Date: 2025-02-20 16:39:34.889953
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
from alembic import op
|
|
11
|
+
from structlog import get_logger
|
|
12
|
+
|
|
13
|
+
logger = get_logger(__name__)
|
|
14
|
+
|
|
15
|
+
# revision identifiers, used by Alembic.
|
|
16
|
+
revision = "68d14db1b8da"
|
|
17
|
+
down_revision = "fc5c993a4b4a"
|
|
18
|
+
branch_labels = None
|
|
19
|
+
depends_on = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def upgrade() -> None:
|
|
23
|
+
try:
|
|
24
|
+
op.alter_column("workflows", "description", existing_type=sa.TEXT(), nullable=False)
|
|
25
|
+
except sa.exc.IntegrityError:
|
|
26
|
+
logger.error(
|
|
27
|
+
"Unable to execute migrations due to missing descriptions in workflow table, please create a migration to backfill this column."
|
|
28
|
+
)
|
|
29
|
+
raise
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def downgrade() -> None:
|
|
33
|
+
op.alter_column("workflows", "description", existing_type=sa.TEXT(), nullable=True)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Add is_task to workflow.
|
|
2
|
+
|
|
3
|
+
Revision ID: 161918133bec
|
|
4
|
+
Revises: 68d14db1b8da
|
|
5
|
+
Create Date: 2025-05-08 11:25:51.966410
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
from alembic import op
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = "161918133bec"
|
|
14
|
+
down_revision = "68d14db1b8da"
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade() -> None:
|
|
20
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
21
|
+
op.add_column("workflows", sa.Column("is_task", sa.Boolean(), server_default=sa.text("false"), nullable=False))
|
|
22
|
+
# ### end Alembic commands ###
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def downgrade() -> None:
|
|
26
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
27
|
+
op.drop_column("workflows", "is_task")
|
|
28
|
+
# ### end Alembic commands ###
|
|
@@ -22,7 +22,7 @@ from orchestrator.services.subscriptions import (
|
|
|
22
22
|
get_subscriptions_on_product_table_in_sync,
|
|
23
23
|
)
|
|
24
24
|
from orchestrator.services.workflows import (
|
|
25
|
-
|
|
25
|
+
get_validation_product_workflows_for_subscription,
|
|
26
26
|
start_validation_workflow_for_workflows,
|
|
27
27
|
)
|
|
28
28
|
from orchestrator.settings import app_settings
|
|
@@ -42,9 +42,9 @@ def validate_subscriptions() -> None:
|
|
|
42
42
|
subscriptions = get_subscriptions_on_product_table_in_sync()
|
|
43
43
|
|
|
44
44
|
for subscription in subscriptions:
|
|
45
|
-
|
|
45
|
+
validation_product_workflows = get_validation_product_workflows_for_subscription(subscription)
|
|
46
46
|
|
|
47
|
-
if not
|
|
47
|
+
if not validation_product_workflows:
|
|
48
48
|
logger.warning(
|
|
49
49
|
"SubscriptionTable has no validation workflow",
|
|
50
50
|
subscription=subscription,
|
|
@@ -52,4 +52,4 @@ def validate_subscriptions() -> None:
|
|
|
52
52
|
)
|
|
53
53
|
break
|
|
54
54
|
|
|
55
|
-
start_validation_workflow_for_workflows(subscription=subscription, workflows=
|
|
55
|
+
start_validation_workflow_for_workflows(subscription=subscription, workflows=validation_product_workflows)
|
orchestrator/schemas/workflow.py
CHANGED
orchestrator/services/celery.py
CHANGED
|
@@ -24,7 +24,7 @@ from orchestrator.api.error_handling import raise_status
|
|
|
24
24
|
from orchestrator.db import ProcessTable, db
|
|
25
25
|
from orchestrator.services.input_state import store_input_state
|
|
26
26
|
from orchestrator.services.processes import create_process, delete_process
|
|
27
|
-
from orchestrator.
|
|
27
|
+
from orchestrator.services.workflows import get_workflow_by_name
|
|
28
28
|
from orchestrator.workflows import get_workflow
|
|
29
29
|
from pydantic_forms.types import State
|
|
30
30
|
|
|
@@ -51,7 +51,11 @@ def _celery_start_process(
|
|
|
51
51
|
if not workflow:
|
|
52
52
|
raise_status(HTTPStatus.NOT_FOUND, "Workflow does not exist")
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
wf_table = get_workflow_by_name(workflow.name)
|
|
55
|
+
if not wf_table:
|
|
56
|
+
raise_status(HTTPStatus.NOT_FOUND, "Workflow in Database does not exist")
|
|
57
|
+
|
|
58
|
+
task_name = NEW_TASK if wf_table.is_task else NEW_WORKFLOW
|
|
55
59
|
trigger_task = get_celery_task(task_name)
|
|
56
60
|
pstat = create_process(workflow_key, user_inputs, user)
|
|
57
61
|
try:
|
|
@@ -80,7 +84,11 @@ def _celery_resume_process(
|
|
|
80
84
|
last_process_status = process.last_status
|
|
81
85
|
workflow = pstat.workflow
|
|
82
86
|
|
|
83
|
-
|
|
87
|
+
wf_table = get_workflow_by_name(workflow.name)
|
|
88
|
+
if not workflow or not wf_table:
|
|
89
|
+
raise_status(HTTPStatus.NOT_FOUND, "Workflow does not exist")
|
|
90
|
+
|
|
91
|
+
task_name = RESUME_TASK if wf_table.is_task else RESUME_WORKFLOW
|
|
84
92
|
trigger_task = get_celery_task(task_name)
|
|
85
93
|
|
|
86
94
|
user_inputs = user_inputs or [{}]
|
|
@@ -34,7 +34,6 @@ from orchestrator.services.input_state import store_input_state
|
|
|
34
34
|
from orchestrator.services.settings import get_engine_settings_for_update
|
|
35
35
|
from orchestrator.services.workflows import get_workflow_by_name
|
|
36
36
|
from orchestrator.settings import ExecutorType, app_settings
|
|
37
|
-
from orchestrator.targets import Target
|
|
38
37
|
from orchestrator.types import BroadcastFunc
|
|
39
38
|
from orchestrator.utils.datetime import nowtz
|
|
40
39
|
from orchestrator.utils.errors import error_state_to_dict
|
|
@@ -108,7 +107,7 @@ def _db_create_process(stat: ProcessStat) -> None:
|
|
|
108
107
|
workflow_id=wf_table.workflow_id,
|
|
109
108
|
last_status=ProcessStatus.CREATED,
|
|
110
109
|
created_by=stat.current_user,
|
|
111
|
-
is_task=
|
|
110
|
+
is_task=wf_table.is_task,
|
|
112
111
|
)
|
|
113
112
|
db.session.add(p)
|
|
114
113
|
db.session.commit()
|
|
@@ -441,6 +440,7 @@ def create_process(
|
|
|
441
440
|
}
|
|
442
441
|
|
|
443
442
|
try:
|
|
443
|
+
|
|
444
444
|
state = post_form(workflow.initial_input_form, initial_state, user_inputs)
|
|
445
445
|
except FormValidationError:
|
|
446
446
|
logger.exception("Validation errors", user_inputs=user_inputs)
|
|
@@ -505,6 +505,7 @@ TARGET_DEFAULT_USABLE_MAP: dict[Target, list[str]] = {
|
|
|
505
505
|
Target.MODIFY: ["active"],
|
|
506
506
|
Target.TERMINATE: ["active", "provisioning"],
|
|
507
507
|
Target.SYSTEM: ["active"],
|
|
508
|
+
Target.VALIDATE: ["active"],
|
|
508
509
|
}
|
|
509
510
|
|
|
510
511
|
WF_USABLE_MAP: dict[str, list[str]] = {}
|
|
@@ -530,6 +531,7 @@ def subscription_workflows(subscription: SubscriptionTable) -> dict[str, Any]:
|
|
|
530
531
|
... "modify": [],
|
|
531
532
|
... "terminate": [],
|
|
532
533
|
... "system": [],
|
|
534
|
+
... "validate": [],
|
|
533
535
|
... }
|
|
534
536
|
|
|
535
537
|
"""
|
|
@@ -549,9 +551,10 @@ def subscription_workflows(subscription: SubscriptionTable) -> dict[str, Any]:
|
|
|
549
551
|
"modify": [],
|
|
550
552
|
"terminate": [],
|
|
551
553
|
"system": [],
|
|
554
|
+
"validate": [],
|
|
552
555
|
}
|
|
553
556
|
for workflow in subscription.product.workflows:
|
|
554
|
-
if workflow.name in WF_USABLE_WHILE_OUT_OF_SYNC or workflow.
|
|
557
|
+
if workflow.name in WF_USABLE_WHILE_OUT_OF_SYNC or workflow.is_task:
|
|
555
558
|
# validations and modify note are also possible with: not in sync or locked relations
|
|
556
559
|
workflow_json = {"name": workflow.name, "description": workflow.description}
|
|
557
560
|
else:
|
|
@@ -605,7 +608,6 @@ def build_domain_model(subscription_model: SubscriptionModel) -> dict:
|
|
|
605
608
|
|
|
606
609
|
def build_extended_domain_model(subscription_model: SubscriptionModel) -> dict:
|
|
607
610
|
"""Create a subscription dict from the SubscriptionModel with additional keys."""
|
|
608
|
-
from orchestrator.settings import app_settings
|
|
609
611
|
|
|
610
612
|
stmt = select(SubscriptionCustomerDescriptionTable).where(
|
|
611
613
|
SubscriptionCustomerDescriptionTable.subscription_id == subscription_model.subscription_id
|
|
@@ -615,27 +617,12 @@ def build_extended_domain_model(subscription_model: SubscriptionModel) -> dict:
|
|
|
615
617
|
with cache_subscription_models():
|
|
616
618
|
subscription = subscription_model.model_dump()
|
|
617
619
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
update_in(subscription, f"{path_to_block}.in_use_by_ids", in_use_by_ids)
|
|
625
|
-
update_in(subscription, f"{path_to_block}.in_use_by_relations", in_use_by_relations)
|
|
626
|
-
|
|
627
|
-
if app_settings.ENABLE_SUBSCRIPTION_MODEL_OPTIMIZATIONS:
|
|
628
|
-
# TODO #900 remove toggle and make this path the default
|
|
629
|
-
# query all subscription instances and inject the in_use_by_ids/in_use_by_relations into the subscription dict.
|
|
630
|
-
instance_to_in_use_by = {
|
|
631
|
-
instance.subscription_instance_id: instance.in_use_by
|
|
632
|
-
for instance in eagerload_all_subscription_instances_only_inuseby(subscription_model.subscription_id)
|
|
633
|
-
}
|
|
634
|
-
inject_in_use_by_ids_v2(subscription, instance_to_in_use_by)
|
|
635
|
-
else:
|
|
636
|
-
# find all product blocks, check if they have in_use_by and inject the in_use_by_ids into the subscription dict.
|
|
637
|
-
for path in product_block_paths(subscription):
|
|
638
|
-
inject_in_use_by_ids(path)
|
|
620
|
+
# query all subscription instances and inject the in_use_by_ids/in_use_by_relations into the subscription dict.
|
|
621
|
+
instance_to_in_use_by = {
|
|
622
|
+
instance.subscription_instance_id: instance.in_use_by
|
|
623
|
+
for instance in eagerload_all_subscription_instances_only_inuseby(subscription_model.subscription_id)
|
|
624
|
+
}
|
|
625
|
+
inject_in_use_by_ids_v2(subscription, instance_to_in_use_by)
|
|
639
626
|
|
|
640
627
|
subscription["customer_descriptions"] = customer_descriptions
|
|
641
628
|
|
|
@@ -39,6 +39,7 @@ def _to_workflow_schema(workflow: WorkflowTable, include_steps: bool = False) ->
|
|
|
39
39
|
workflow_id=workflow.workflow_id,
|
|
40
40
|
name=workflow.name,
|
|
41
41
|
target=workflow.target,
|
|
42
|
+
is_task=workflow.is_task,
|
|
42
43
|
description=workflow.description,
|
|
43
44
|
created_at=workflow.created_at,
|
|
44
45
|
**extra_kwargs,
|
|
@@ -63,10 +64,10 @@ def get_workflow_by_name(workflow_name: str) -> WorkflowTable | None:
|
|
|
63
64
|
return db.session.scalar(select(WorkflowTable).where(WorkflowTable.name == workflow_name))
|
|
64
65
|
|
|
65
66
|
|
|
66
|
-
def
|
|
67
|
+
def get_validation_product_workflows_for_subscription(
|
|
67
68
|
subscription: SubscriptionTable,
|
|
68
69
|
) -> list:
|
|
69
|
-
return [workflow.name for workflow in subscription.product.workflows if workflow.target == Target.
|
|
70
|
+
return [workflow.name for workflow in subscription.product.workflows if workflow.target == Target.VALIDATE]
|
|
70
71
|
|
|
71
72
|
|
|
72
73
|
def start_validation_workflow_for_workflows(
|
|
@@ -78,9 +79,12 @@ def start_validation_workflow_for_workflows(
|
|
|
78
79
|
result = []
|
|
79
80
|
|
|
80
81
|
for workflow_name in workflows:
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
target_system = TARGET_DEFAULT_USABLE_MAP[Target.SYSTEM]
|
|
83
|
+
system_usable_when = WF_USABLE_MAP.get(workflow_name, target_system)
|
|
84
|
+
target_validate = TARGET_DEFAULT_USABLE_MAP[Target.VALIDATE]
|
|
85
|
+
validate_usable_when = WF_USABLE_MAP.get(workflow_name, target_validate)
|
|
83
86
|
|
|
87
|
+
usable_when = system_usable_when + validate_usable_when
|
|
84
88
|
if subscription.status in usable_when and (
|
|
85
89
|
product_type_filter is None or subscription.product.product_type == product_type_filter
|
|
86
90
|
):
|
orchestrator/settings.py
CHANGED
|
@@ -55,7 +55,6 @@ class AppSettings(BaseSettings):
|
|
|
55
55
|
MAIL_PORT: int = 25
|
|
56
56
|
MAIL_STARTTLS: bool = False
|
|
57
57
|
CACHE_URI: RedisDsn = "redis://localhost:6379/0" # type: ignore
|
|
58
|
-
CACHE_DOMAIN_MODELS: bool = False
|
|
59
58
|
CACHE_HMAC_SECRET: str | None = None # HMAC signing key, used when pickling results in the cache
|
|
60
59
|
REDIS_RETRY_COUNT: NonNegativeInt = Field(
|
|
61
60
|
2, description="Number of retries for redis connection errors/timeouts, 0 to disable"
|
|
@@ -87,9 +86,6 @@ class AppSettings(BaseSettings):
|
|
|
87
86
|
ENABLE_GRAPHQL_STATS_EXTENSION: bool = False
|
|
88
87
|
VALIDATE_OUT_OF_SYNC_SUBSCRIPTIONS: bool = False
|
|
89
88
|
FILTER_BY_MODE: Literal["partial", "exact"] = "exact"
|
|
90
|
-
ENABLE_SUBSCRIPTION_MODEL_OPTIMIZATIONS: bool = (
|
|
91
|
-
True # True=ignore cache + optimized DB queries; False=use cache + unoptimized DB queries. Remove in #900
|
|
92
|
-
)
|
|
93
89
|
|
|
94
90
|
|
|
95
91
|
app_settings = AppSettings()
|
orchestrator/targets.py
CHANGED
|
@@ -2,15 +2,11 @@ from uuid import UUID
|
|
|
2
2
|
|
|
3
3
|
from orchestrator.domain.base import SubscriptionModel
|
|
4
4
|
from orchestrator.services.subscriptions import _generate_etag, build_domain_model, build_extended_domain_model
|
|
5
|
-
from orchestrator.utils.redis import from_redis
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
async def get_subscription_dict(subscription_id: UUID, inject_inuseby: bool = True) -> tuple[dict, str]:
|
|
9
8
|
"""Helper function to get subscription dict by uuid from db or cache."""
|
|
10
9
|
|
|
11
|
-
if cached_model := from_redis(subscription_id):
|
|
12
|
-
return cached_model # type: ignore
|
|
13
|
-
|
|
14
10
|
subscription_model = SubscriptionModel.from_subscription(subscription_id)
|
|
15
11
|
|
|
16
12
|
if not inject_inuseby:
|
orchestrator/utils/redis.py
CHANGED
|
@@ -10,11 +10,9 @@
|
|
|
10
10
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
|
-
import functools
|
|
14
13
|
from collections.abc import AsyncGenerator
|
|
15
14
|
from contextlib import asynccontextmanager
|
|
16
|
-
from
|
|
17
|
-
from typing import Any, Callable
|
|
15
|
+
from typing import Any
|
|
18
16
|
from uuid import UUID
|
|
19
17
|
|
|
20
18
|
from anyio import CancelScope, get_cancelled_exc_class
|
|
@@ -22,9 +20,7 @@ from redis.asyncio import Redis as AIORedis
|
|
|
22
20
|
from redis.asyncio.client import Pipeline, PubSub
|
|
23
21
|
from structlog import get_logger
|
|
24
22
|
|
|
25
|
-
from orchestrator.services.subscriptions import _generate_etag
|
|
26
23
|
from orchestrator.settings import app_settings
|
|
27
|
-
from orchestrator.utils.json import PY_JSON_TYPES, json_dumps, json_loads
|
|
28
24
|
from orchestrator.utils.redis_client import (
|
|
29
25
|
create_redis_asyncio_client,
|
|
30
26
|
create_redis_client,
|
|
@@ -37,52 +33,6 @@ cache = create_redis_client(app_settings.CACHE_URI)
|
|
|
37
33
|
ONE_WEEK = 3600 * 24 * 7
|
|
38
34
|
|
|
39
35
|
|
|
40
|
-
def caching_models_enabled() -> bool:
|
|
41
|
-
return getenv("AIOCACHE_DISABLE", "0") == "0" and app_settings.CACHE_DOMAIN_MODELS
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def to_redis(subscription: dict[str, Any]) -> str | None:
|
|
45
|
-
if caching_models_enabled():
|
|
46
|
-
logger.info("Setting cache for subscription", subscription=subscription["subscription_id"])
|
|
47
|
-
etag = _generate_etag(subscription)
|
|
48
|
-
cache.set(f"orchestrator:domain:{subscription['subscription_id']}", json_dumps(subscription), ex=ONE_WEEK)
|
|
49
|
-
cache.set(f"orchestrator:domain:etag:{subscription['subscription_id']}", etag, ex=ONE_WEEK)
|
|
50
|
-
return etag
|
|
51
|
-
|
|
52
|
-
logger.warning("Caching disabled, not caching subscription", subscription=subscription["subscription_id"])
|
|
53
|
-
return None
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def from_redis(subscription_id: UUID) -> tuple[PY_JSON_TYPES, str] | None:
|
|
57
|
-
log = logger.bind(subscription_id=subscription_id)
|
|
58
|
-
|
|
59
|
-
if app_settings.ENABLE_SUBSCRIPTION_MODEL_OPTIMIZATIONS:
|
|
60
|
-
# TODO #900 remove toggle and remove usage of this function in get_subscription_dict
|
|
61
|
-
log.info("Using SubscriptionModel optimization, not loading subscription from redis cache")
|
|
62
|
-
return None
|
|
63
|
-
|
|
64
|
-
if caching_models_enabled():
|
|
65
|
-
log.debug("Try to retrieve subscription from cache")
|
|
66
|
-
obj = cache.get(f"orchestrator:domain:{subscription_id}")
|
|
67
|
-
etag = cache.get(f"orchestrator:domain:etag:{subscription_id}")
|
|
68
|
-
if obj and etag:
|
|
69
|
-
log.info("Retrieved subscription from cache")
|
|
70
|
-
return json_loads(obj), etag.decode("utf-8")
|
|
71
|
-
log.info("Subscription not found in cache")
|
|
72
|
-
return None
|
|
73
|
-
log.warning("Caching disabled, not loading subscription")
|
|
74
|
-
return None
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def delete_from_redis(subscription_id: UUID) -> None:
|
|
78
|
-
if caching_models_enabled():
|
|
79
|
-
logger.info("Deleting subscription object from cache", subscription_id=subscription_id)
|
|
80
|
-
cache.delete(f"orchestrator:domain:{subscription_id}")
|
|
81
|
-
cache.delete(f"orchestrator:domain:etag:{subscription_id}")
|
|
82
|
-
else:
|
|
83
|
-
logger.warning("Caching disabled, not deleting subscription", subscription=subscription_id)
|
|
84
|
-
|
|
85
|
-
|
|
86
36
|
def default_get_subscription_id(data: Any) -> UUID:
|
|
87
37
|
if hasattr(data, "subscription_id"):
|
|
88
38
|
return data.subscription_id
|
|
@@ -91,22 +41,6 @@ def default_get_subscription_id(data: Any) -> UUID:
|
|
|
91
41
|
return data
|
|
92
42
|
|
|
93
43
|
|
|
94
|
-
def delete_subscription_from_redis(
|
|
95
|
-
extract_fn: Callable[..., UUID] = default_get_subscription_id,
|
|
96
|
-
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
97
|
-
def _delete_subscription_from_redis(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
98
|
-
@functools.wraps(func)
|
|
99
|
-
async def wrapper(*args: tuple, **kwargs: dict[str, Any]) -> Any:
|
|
100
|
-
data = await func(*args, **kwargs)
|
|
101
|
-
key = extract_fn(data)
|
|
102
|
-
delete_from_redis(key)
|
|
103
|
-
return data
|
|
104
|
-
|
|
105
|
-
return wrapper
|
|
106
|
-
|
|
107
|
-
return _delete_subscription_from_redis
|
|
108
|
-
|
|
109
|
-
|
|
110
44
|
async def delete_keys_matching_pattern(_cache: AIORedis, pattern: str, chunksize: int = 5000) -> int:
|
|
111
45
|
"""Delete all keys matching the given pattern.
|
|
112
46
|
|
|
@@ -13,11 +13,10 @@
|
|
|
13
13
|
from orchestrator.db import db
|
|
14
14
|
from orchestrator.forms import SubmitFormPage
|
|
15
15
|
from orchestrator.services import subscriptions
|
|
16
|
-
from orchestrator.settings import app_settings
|
|
17
16
|
from orchestrator.targets import Target
|
|
18
17
|
from orchestrator.utils.json import to_serializable
|
|
19
|
-
from orchestrator.workflow import StepList,
|
|
20
|
-
from orchestrator.workflows.steps import
|
|
18
|
+
from orchestrator.workflow import StepList, done, init, step, workflow
|
|
19
|
+
from orchestrator.workflows.steps import store_process_subscription
|
|
21
20
|
from orchestrator.workflows.utils import wrap_modify_initial_input_form
|
|
22
21
|
from pydantic_forms.types import FormGenerator, State, UUIDstr
|
|
23
22
|
from pydantic_forms.validators import LongText
|
|
@@ -54,11 +53,4 @@ def store_subscription_note(subscription_id: UUIDstr, note: str) -> State:
|
|
|
54
53
|
|
|
55
54
|
@workflow("Modify Note", initial_input_form=wrap_modify_initial_input_form(initial_input_form), target=Target.MODIFY)
|
|
56
55
|
def modify_note() -> StepList:
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
init
|
|
60
|
-
>> store_process_subscription(Target.MODIFY)
|
|
61
|
-
>> store_subscription_note
|
|
62
|
-
>> push_subscriptions(cache_domain_models)
|
|
63
|
-
>> done
|
|
64
|
-
)
|
|
56
|
+
return init >> store_process_subscription(Target.MODIFY) >> store_subscription_note >> done
|
orchestrator/workflows/steps.py
CHANGED
|
@@ -11,22 +11,18 @@
|
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
from copy import deepcopy
|
|
14
|
-
from typing import Any
|
|
15
|
-
from uuid import UUID
|
|
16
14
|
|
|
17
15
|
import structlog
|
|
18
16
|
from pydantic import ValidationError
|
|
19
17
|
|
|
20
18
|
from orchestrator.db import db
|
|
21
19
|
from orchestrator.db.models import ProcessSubscriptionTable
|
|
22
|
-
from orchestrator.domain.base import
|
|
20
|
+
from orchestrator.domain.base import SubscriptionModel
|
|
23
21
|
from orchestrator.services.settings import reset_search_index
|
|
24
|
-
from orchestrator.services.subscriptions import
|
|
22
|
+
from orchestrator.services.subscriptions import get_subscription
|
|
25
23
|
from orchestrator.targets import Target
|
|
26
24
|
from orchestrator.types import SubscriptionLifecycle
|
|
27
25
|
from orchestrator.utils.json import to_serializable
|
|
28
|
-
from orchestrator.utils.redis import delete_from_redis, to_redis
|
|
29
|
-
from orchestrator.websocket import sync_invalidate_subscription_cache
|
|
30
26
|
from orchestrator.workflow import Step, step
|
|
31
27
|
from pydantic_forms.types import State, UUIDstr
|
|
32
28
|
|
|
@@ -138,86 +134,6 @@ def set_status(status: SubscriptionLifecycle) -> Step:
|
|
|
138
134
|
return _set_status
|
|
139
135
|
|
|
140
136
|
|
|
141
|
-
@step("Remove domain model from cache")
|
|
142
|
-
def remove_domain_model_from_cache(
|
|
143
|
-
workflow_name: str, subscription: SubscriptionModel | None = None, subscription_id: UUID | None = None
|
|
144
|
-
) -> State:
|
|
145
|
-
"""Remove the domain model from the cache if it exists.
|
|
146
|
-
|
|
147
|
-
Args:
|
|
148
|
-
workflow_name: The workflow name
|
|
149
|
-
subscription: Subscription Model
|
|
150
|
-
subscription_id: The subscription id
|
|
151
|
-
|
|
152
|
-
Returns:
|
|
153
|
-
State
|
|
154
|
-
|
|
155
|
-
"""
|
|
156
|
-
|
|
157
|
-
if not (subscription or subscription_id):
|
|
158
|
-
logger.warning("No subscription found in this workflow", workflow_name=workflow_name)
|
|
159
|
-
return {"deleted_subscription_id": None}
|
|
160
|
-
if subscription:
|
|
161
|
-
delete_from_redis(subscription.subscription_id)
|
|
162
|
-
elif subscription_id:
|
|
163
|
-
delete_from_redis(subscription_id)
|
|
164
|
-
|
|
165
|
-
return {"deleted_subscription_id": subscription_id or subscription.subscription_id} # type: ignore[union-attr]
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
@step("Cache Subscription and related subscriptions")
|
|
169
|
-
def cache_domain_models(workflow_name: str, subscription: SubscriptionModel | None = None) -> State: # noqa: C901
|
|
170
|
-
"""Attempt to cache all Subscriptions once they have been touched once.
|
|
171
|
-
|
|
172
|
-
Args:
|
|
173
|
-
workflow_name: The Workflow Name
|
|
174
|
-
subscription: The Subscription if it exists.
|
|
175
|
-
|
|
176
|
-
Returns:
|
|
177
|
-
Returns State.
|
|
178
|
-
|
|
179
|
-
"""
|
|
180
|
-
cached_subscription_ids: set[UUID] = set()
|
|
181
|
-
if not subscription:
|
|
182
|
-
logger.warning("No subscription found in this workflow", workflow_name=workflow_name)
|
|
183
|
-
return {"cached_subscription_ids": cached_subscription_ids}
|
|
184
|
-
|
|
185
|
-
def _cache_other_subscriptions(product_block: ProductBlockModel) -> None:
|
|
186
|
-
for field in product_block.model_fields:
|
|
187
|
-
# subscription_instance is a ProductBlockModel or an arbitrary type
|
|
188
|
-
subscription_instance: ProductBlockModel | Any = getattr(product_block, field)
|
|
189
|
-
# If subscription_instance is a list, we need to step into it and loop.
|
|
190
|
-
if isinstance(subscription_instance, list):
|
|
191
|
-
for item in subscription_instance:
|
|
192
|
-
if isinstance(item, ProductBlockModel):
|
|
193
|
-
_cache_other_subscriptions(item)
|
|
194
|
-
|
|
195
|
-
# If subscription_instance is a ProductBlockModel check the owner_subscription_id to decide the cache
|
|
196
|
-
elif isinstance(subscription_instance, ProductBlockModel):
|
|
197
|
-
_cache_other_subscriptions(subscription_instance)
|
|
198
|
-
if not subscription_instance.owner_subscription_id == subscription.subscription_id:
|
|
199
|
-
cached_subscription_ids.add(subscription_instance.owner_subscription_id)
|
|
200
|
-
|
|
201
|
-
for field in subscription.model_fields:
|
|
202
|
-
# There always is a single Root Product Block, it cannot be a list, so no need to check.
|
|
203
|
-
instance: ProductBlockModel | Any = getattr(subscription, field)
|
|
204
|
-
if isinstance(instance, ProductBlockModel):
|
|
205
|
-
_cache_other_subscriptions(instance)
|
|
206
|
-
|
|
207
|
-
# Cache all the sub subscriptions
|
|
208
|
-
for subscription_id in cached_subscription_ids:
|
|
209
|
-
subscription_model = SubscriptionModel.from_subscription(subscription_id)
|
|
210
|
-
to_redis(build_extended_domain_model(subscription_model))
|
|
211
|
-
sync_invalidate_subscription_cache(subscription.subscription_id, invalidate_all=False)
|
|
212
|
-
|
|
213
|
-
# Cache the main subscription
|
|
214
|
-
to_redis(build_extended_domain_model(subscription))
|
|
215
|
-
cached_subscription_ids.add(subscription.subscription_id)
|
|
216
|
-
sync_invalidate_subscription_cache(subscription.subscription_id)
|
|
217
|
-
|
|
218
|
-
return {"cached_subscription_ids": cached_subscription_ids}
|
|
219
|
-
|
|
220
|
-
|
|
221
137
|
@step("Refresh subscription search index")
|
|
222
138
|
def refresh_subscription_search_index() -> State:
|
|
223
139
|
try:
|
|
@@ -22,7 +22,7 @@ from orchestrator.services.subscriptions import (
|
|
|
22
22
|
get_subscriptions_on_product_table_in_sync,
|
|
23
23
|
)
|
|
24
24
|
from orchestrator.services.workflows import (
|
|
25
|
-
|
|
25
|
+
get_validation_product_workflows_for_subscription,
|
|
26
26
|
start_validation_workflow_for_workflows,
|
|
27
27
|
)
|
|
28
28
|
from orchestrator.targets import Target
|
|
@@ -62,7 +62,7 @@ def validate_product_type(product_type: str) -> State:
|
|
|
62
62
|
subscriptions = get_subscriptions_on_product_table_in_sync()
|
|
63
63
|
|
|
64
64
|
for subscription in subscriptions:
|
|
65
|
-
system_product_workflows =
|
|
65
|
+
system_product_workflows = get_validation_product_workflows_for_subscription(
|
|
66
66
|
subscription=subscription,
|
|
67
67
|
)
|
|
68
68
|
|
|
@@ -105,13 +105,10 @@ def check_that_products_have_create_modify_and_terminate_workflows() -> State:
|
|
|
105
105
|
product_data = get_products(filters=[ProductTable.status == "active"])
|
|
106
106
|
|
|
107
107
|
workflows_not_complete: list = []
|
|
108
|
+
targets = ["CREATE", "TERMINATE", "MODIFY", "VALIDATE"]
|
|
108
109
|
for product in product_data:
|
|
109
|
-
workflows = {
|
|
110
|
-
|
|
111
|
-
for c in product.workflows
|
|
112
|
-
if c.target in ["CREATE", "TERMINATE", "MODIFY", "SYSTEM"] and c.name != "modify_note"
|
|
113
|
-
}
|
|
114
|
-
if len(workflows) < 4:
|
|
110
|
+
workflows = {c.target for c in product.workflows if c.target in targets and c.name != "modify_note"}
|
|
111
|
+
if len(workflows) < len(targets):
|
|
115
112
|
workflows_not_complete.append(product.name)
|
|
116
113
|
|
|
117
114
|
# Do not raise an error but only report it in the `State` to allow exceptions.
|
orchestrator/workflows/utils.py
CHANGED
|
@@ -24,16 +24,13 @@ from oauth2_lib.fastapi import OIDCUserModel
|
|
|
24
24
|
from orchestrator.db import ProductTable, SubscriptionTable, db
|
|
25
25
|
from orchestrator.forms.validators import ProductId
|
|
26
26
|
from orchestrator.services import subscriptions
|
|
27
|
-
from orchestrator.settings import app_settings
|
|
28
27
|
from orchestrator.targets import Target
|
|
29
28
|
from orchestrator.types import SubscriptionLifecycle
|
|
30
29
|
from orchestrator.utils.errors import StaleDataError
|
|
31
|
-
from orchestrator.utils.redis import caching_models_enabled
|
|
32
30
|
from orchestrator.utils.state import form_inject_args
|
|
33
31
|
from orchestrator.utils.validate_data_version import validate_data_version
|
|
34
|
-
from orchestrator.workflow import Step, StepList, Workflow, begin,
|
|
32
|
+
from orchestrator.workflow import Step, StepList, Workflow, begin, done, init, make_workflow, step
|
|
35
33
|
from orchestrator.workflows.steps import (
|
|
36
|
-
cache_domain_models,
|
|
37
34
|
refresh_subscription_search_index,
|
|
38
35
|
resync,
|
|
39
36
|
set_status,
|
|
@@ -198,8 +195,6 @@ modify_initial_input_form_generator = None
|
|
|
198
195
|
|
|
199
196
|
validate_initial_input_form_generator = wrap_modify_initial_input_form(modify_initial_input_form_generator)
|
|
200
197
|
|
|
201
|
-
push_domain_models = conditional(lambda _: caching_models_enabled())
|
|
202
|
-
|
|
203
198
|
|
|
204
199
|
def create_workflow(
|
|
205
200
|
description: str,
|
|
@@ -228,7 +223,6 @@ def create_workflow(
|
|
|
228
223
|
>> (additional_steps or StepList())
|
|
229
224
|
>> set_status(status)
|
|
230
225
|
>> resync
|
|
231
|
-
>> push_domain_models(cache_domain_models)
|
|
232
226
|
>> refresh_subscription_search_index
|
|
233
227
|
>> done
|
|
234
228
|
)
|
|
@@ -270,11 +264,9 @@ def modify_workflow(
|
|
|
270
264
|
init
|
|
271
265
|
>> store_process_subscription(Target.MODIFY)
|
|
272
266
|
>> unsync
|
|
273
|
-
>> push_domain_models(cache_domain_models)
|
|
274
267
|
>> f()
|
|
275
268
|
>> (additional_steps or StepList())
|
|
276
269
|
>> resync
|
|
277
|
-
>> push_domain_models(cache_domain_models)
|
|
278
270
|
>> refresh_subscription_search_index
|
|
279
271
|
>> done
|
|
280
272
|
)
|
|
@@ -316,12 +308,10 @@ def terminate_workflow(
|
|
|
316
308
|
init
|
|
317
309
|
>> store_process_subscription(Target.TERMINATE)
|
|
318
310
|
>> unsync
|
|
319
|
-
>> push_domain_models(cache_domain_models)
|
|
320
311
|
>> f()
|
|
321
312
|
>> (additional_steps or StepList())
|
|
322
313
|
>> set_status(SubscriptionLifecycle.TERMINATED)
|
|
323
314
|
>> resync
|
|
324
|
-
>> push_domain_models(cache_domain_models)
|
|
325
315
|
>> refresh_subscription_search_index
|
|
326
316
|
>> done
|
|
327
317
|
)
|
|
@@ -352,19 +342,9 @@ def validate_workflow(description: str) -> Callable[[Callable[[], StepList]], Wo
|
|
|
352
342
|
"""
|
|
353
343
|
|
|
354
344
|
def _validate_workflow(f: Callable[[], StepList]) -> Workflow:
|
|
355
|
-
|
|
356
|
-
steplist = (
|
|
357
|
-
init
|
|
358
|
-
>> store_process_subscription(Target.SYSTEM)
|
|
359
|
-
>> unsync_unchecked
|
|
360
|
-
>> push_subscriptions(cache_domain_models)
|
|
361
|
-
>> f()
|
|
362
|
-
>> resync
|
|
363
|
-
>> push_subscriptions(cache_domain_models)
|
|
364
|
-
>> done
|
|
365
|
-
)
|
|
345
|
+
steplist = init >> store_process_subscription(Target.SYSTEM) >> unsync_unchecked >> f() >> resync >> done
|
|
366
346
|
|
|
367
|
-
return make_workflow(f, description, validate_initial_input_form_generator, Target.
|
|
347
|
+
return make_workflow(f, description, validate_initial_input_form_generator, Target.VALIDATE, steplist)
|
|
368
348
|
|
|
369
349
|
return _validate_workflow
|
|
370
350
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: orchestrator-core
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0rc2
|
|
4
4
|
Summary: This is the orchestrator workflow engine.
|
|
5
5
|
Requires-Python: >=3.11,<3.14
|
|
6
6
|
Classifier: Intended Audience :: Information Technology
|
|
@@ -35,24 +35,24 @@ Requires-Dist: deprecated
|
|
|
35
35
|
Requires-Dist: deepmerge==2.0
|
|
36
36
|
Requires-Dist: fastapi~=0.115.2
|
|
37
37
|
Requires-Dist: fastapi-etag==0.4.0
|
|
38
|
-
Requires-Dist: more-itertools~=10.
|
|
38
|
+
Requires-Dist: more-itertools~=10.7.0
|
|
39
39
|
Requires-Dist: itsdangerous
|
|
40
40
|
Requires-Dist: Jinja2==3.1.6
|
|
41
|
-
Requires-Dist: orjson==3.10.
|
|
41
|
+
Requires-Dist: orjson==3.10.18
|
|
42
42
|
Requires-Dist: psycopg2-binary==2.9.10
|
|
43
43
|
Requires-Dist: pydantic[email]~=2.8.2
|
|
44
|
-
Requires-Dist: pydantic-settings~=2.
|
|
44
|
+
Requires-Dist: pydantic-settings~=2.9.1
|
|
45
45
|
Requires-Dist: python-dateutil==2.8.2
|
|
46
46
|
Requires-Dist: python-rapidjson>=1.18,<1.21
|
|
47
47
|
Requires-Dist: pytz==2025.2
|
|
48
48
|
Requires-Dist: redis==5.1.1
|
|
49
49
|
Requires-Dist: schedule==1.1.0
|
|
50
50
|
Requires-Dist: semver==3.0.4
|
|
51
|
-
Requires-Dist: sentry-sdk[fastapi]~=2.
|
|
51
|
+
Requires-Dist: sentry-sdk[fastapi]~=2.27.0
|
|
52
52
|
Requires-Dist: SQLAlchemy==2.0.40
|
|
53
53
|
Requires-Dist: SQLAlchemy-Utils==0.41.2
|
|
54
54
|
Requires-Dist: structlog
|
|
55
|
-
Requires-Dist: typer==0.15.
|
|
55
|
+
Requires-Dist: typer==0.15.3
|
|
56
56
|
Requires-Dist: uvicorn[standard]~=0.34.0
|
|
57
57
|
Requires-Dist: nwa-stdlib~=1.9.0
|
|
58
58
|
Requires-Dist: oauth2-lib~=2.4.0
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
orchestrator/__init__.py,sha256=
|
|
1
|
+
orchestrator/__init__.py,sha256=_4qDYGxoCurHceKtJMPSdPiXXCzkD0XpCJiQy6gBP5g,1066
|
|
2
2
|
orchestrator/app.py,sha256=VN54_Zsx5x_3ym8aFadATg67a4J5lv8H-pxnPlR3RkM,11668
|
|
3
3
|
orchestrator/exception_handlers.py,sha256=UsW3dw8q0QQlNLcV359bIotah8DYjMsj2Ts1LfX4ClY,1268
|
|
4
4
|
orchestrator/log_config.py,sha256=1tPRX5q65e57a6a_zEii_PFK8SzWT0mnA5w2sKg4hh8,1853
|
|
5
5
|
orchestrator/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
orchestrator/security.py,sha256=iXFxGxab54aav7oHEKLAVkTgrQMJGHy6IYLojEnD7gI,2422
|
|
7
|
-
orchestrator/settings.py,sha256=
|
|
8
|
-
orchestrator/targets.py,sha256=
|
|
7
|
+
orchestrator/settings.py,sha256=21BT1SviPllSL4-M1Qc-8zdgF_Sh7p79WC8sR_AmTmE,3826
|
|
8
|
+
orchestrator/targets.py,sha256=WizBgnp8hWX9YLFUIju7ewSubiwQqinCvyiYNcXHbHI,802
|
|
9
9
|
orchestrator/types.py,sha256=qzs7xx5AYRmKbpYRyJJP3wuDb0W0bcAzefCN0RWLAco,15459
|
|
10
10
|
orchestrator/version.py,sha256=b58e08lxs47wUNXv0jXFO_ykpksmytuzEXD4La4W-NQ,1366
|
|
11
11
|
orchestrator/workflow.py,sha256=T_3Z1PrlF70C16ehAthKRF1hd3jpwV-MREDVxSLfxOw,44063
|
|
@@ -22,7 +22,7 @@ orchestrator/api/api_v1/endpoints/product_blocks.py,sha256=kZ6ywIOsS_S2qGq7RvZ4K
|
|
|
22
22
|
orchestrator/api/api_v1/endpoints/products.py,sha256=BfFtwu9dZXEQbtKxYj9icc73GKGvAGMR5ytyf41nQlQ,3081
|
|
23
23
|
orchestrator/api/api_v1/endpoints/resource_types.py,sha256=gGyuaDyOD0TAVoeFGaGmjDGnQ8eQQArOxKrrk4MaDzA,2145
|
|
24
24
|
orchestrator/api/api_v1/endpoints/settings.py,sha256=QPBwrRGqBlYHNRnADKQ5hpj74X2DB5lROu8KwVnyN_0,6226
|
|
25
|
-
orchestrator/api/api_v1/endpoints/subscription_customer_descriptions.py,sha256=
|
|
25
|
+
orchestrator/api/api_v1/endpoints/subscription_customer_descriptions.py,sha256=1_6LtgQleoq3M6z_W-Qz__Bj3OFUweoPrUqHMwSH6AM,3288
|
|
26
26
|
orchestrator/api/api_v1/endpoints/subscriptions.py,sha256=EwkWBztI9xSMPkol49SM5csECthyu7HC38AhuW7pWUE,8724
|
|
27
27
|
orchestrator/api/api_v1/endpoints/translations.py,sha256=dIWh_fCnZZUxJoGiNeJ49DK_xpf75IpR_0EIMSvzIvY,963
|
|
28
28
|
orchestrator/api/api_v1/endpoints/user.py,sha256=RyI32EXVu6I-IxWjz0XB5zQWzzLL60zKXLgLqLH02xU,1827
|
|
@@ -33,8 +33,8 @@ orchestrator/cli/database.py,sha256=qig-WqUtiDITz4KePxzcqZtC0FPTWRs_3l19qQpqIGA,
|
|
|
33
33
|
orchestrator/cli/generate.py,sha256=SBaYfRijXPF9r3VxarPKTiDzDcB6GBMMQvecQIb_ZLQ,7377
|
|
34
34
|
orchestrator/cli/main.py,sha256=GC_kxa9OZ-Y0ig_klfWc6ysOQuPVTUmTmDRj3m8cJHA,983
|
|
35
35
|
orchestrator/cli/migrate_domain_models.py,sha256=OhjNuIheytgShpMYCZ18leNUzk17ExhtkCqx7Ww03R8,20371
|
|
36
|
-
orchestrator/cli/migrate_tasks.py,sha256=
|
|
37
|
-
orchestrator/cli/migrate_workflows.py,sha256
|
|
36
|
+
orchestrator/cli/migrate_tasks.py,sha256=bju8XColjSZD0v3rS4kl-24dLr8En_H4-6enBmqd494,7255
|
|
37
|
+
orchestrator/cli/migrate_workflows.py,sha256=nxUpx0vgEIc_8aJrjAyrw3E9Dt8JmaamTts8oiQ4vHY,8923
|
|
38
38
|
orchestrator/cli/migration_helpers.py,sha256=C5tpkP5WEBr7G9S-1k1hgSI8ili6xd9Z5ygc9notaK0,4110
|
|
39
39
|
orchestrator/cli/scheduler.py,sha256=iCKBWYUwQIYTDqKQ9rMVvs2sNiAzE-J2SkV170TPP2g,1896
|
|
40
40
|
orchestrator/cli/domain_gen_helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -83,7 +83,7 @@ orchestrator/cli/generator/templates/lazy_workflow_instance.j2,sha256=BYB6LwE19O
|
|
|
83
83
|
orchestrator/cli/generator/templates/list_definitions.j2,sha256=XS-F5XXy4HOdsZ-xahprwxfhU0UaiF4VeopkIxfoado,277
|
|
84
84
|
orchestrator/cli/generator/templates/macros.j2,sha256=fEODRym4gLfL40w9OelXFMDtAjtzmN5nccWDk86oTNI,904
|
|
85
85
|
orchestrator/cli/generator/templates/modify_product.j2,sha256=M1WDMmPwfXpUcuZUa-H5GnlKAr1t_xCQliLa66FI-YU,5057
|
|
86
|
-
orchestrator/cli/generator/templates/new_product_migration.j2,sha256=
|
|
86
|
+
orchestrator/cli/generator/templates/new_product_migration.j2,sha256=XTeOmv8nVNfGXx6pfSGVwRk282Xx3lnw-7bkpHkd-Tk,3128
|
|
87
87
|
orchestrator/cli/generator/templates/product.j2,sha256=gcN1poWRuGWbsLrQv0Z8SXO6MGuXBHBr33UvQtqsF8E,1241
|
|
88
88
|
orchestrator/cli/generator/templates/product_block.j2,sha256=X5ynyBG39UiYekPHms7IkSHmxq2j-2OrhAYsFaRqktU,2454
|
|
89
89
|
orchestrator/cli/generator/templates/shared_forms.j2,sha256=tXbauuMMExwHLYLJVkmAJ74SSFriXlwpOyd04jwWE0k,545
|
|
@@ -106,7 +106,7 @@ orchestrator/db/database.py,sha256=MU_w_e95ho2dVb2JDnt_KFYholx___XDkiQXbc8wCkI,1
|
|
|
106
106
|
orchestrator/db/helpers.py,sha256=L8kEdnSSNGnUpZhdeGx2arCodakWN8vSpKdfjoLuHdY,831
|
|
107
107
|
orchestrator/db/listeners.py,sha256=UBPYcH0FE3a7aZQu_D0O_JMXpXIRYXC0gjSAvlv5GZo,1142
|
|
108
108
|
orchestrator/db/loaders.py,sha256=ez6JzQ3IKVkC_oLAkVlIIiI8Do7hXbdcPKCvUSLxRog,7962
|
|
109
|
-
orchestrator/db/models.py,sha256=
|
|
109
|
+
orchestrator/db/models.py,sha256=92lkqI4u3Si2tEMSTnMb5Uv08CSjqkgotgyEYqLvFeI,27302
|
|
110
110
|
orchestrator/db/filters/__init__.py,sha256=RUj6P0XxEBhYj0SN5wH5-Vf_Wt_ilZR_n9DSar5m9oM,371
|
|
111
111
|
orchestrator/db/filters/filters.py,sha256=55RtpQwM2rhrk4A6CCSeSXoo-BT9GnQoNTryA8CtLEg,5020
|
|
112
112
|
orchestrator/db/filters/process.py,sha256=xvGhyfo_MZ1xhLvFC6yULjcT4mJk0fKc1glJIYgsWLE,4018
|
|
@@ -142,9 +142,9 @@ orchestrator/distlock/managers/__init__.py,sha256=ImIkNsrXcyE7-NgRWqEhUXUuUzda9K
|
|
|
142
142
|
orchestrator/distlock/managers/memory_distlock_manager.py,sha256=HWQafcVKBF-Cka_wukZZ1GM69AWPVOpJPje3quIebQ8,3114
|
|
143
143
|
orchestrator/distlock/managers/redis_distlock_manager.py,sha256=DXtMhC8qtxiFO6xU9qYXHZQnCLjlmGBpeyfLA0vbRP0,3369
|
|
144
144
|
orchestrator/domain/__init__.py,sha256=20DhXQPKY0g3rTgCkRlNDY58sLviToOVF8NPoex9WJc,936
|
|
145
|
-
orchestrator/domain/base.py,sha256=
|
|
145
|
+
orchestrator/domain/base.py,sha256=jjMxJvt0GyaTff_z490lmkqDCtitkh0oA4GygB60n4s,69939
|
|
146
146
|
orchestrator/domain/context_cache.py,sha256=vT1a01MBSBIaokoShK9KwjItd7abNmz7cXaF67VRZK8,2508
|
|
147
|
-
orchestrator/domain/customer_description.py,sha256=
|
|
147
|
+
orchestrator/domain/customer_description.py,sha256=RU_pcgCIZjjFfDsY45lfV0z6ATlS1NXtB0E7eH3UcYQ,3190
|
|
148
148
|
orchestrator/domain/helpers.py,sha256=D9O2duhCAZGmm39u-9ggvU-X2JsCbIS607kF77-r8QM,2549
|
|
149
149
|
orchestrator/domain/lifecycle.py,sha256=kGR0AFVOSUBlzdhgRr11CUnF26wbBYIjz8uKb_qPCg0,2922
|
|
150
150
|
orchestrator/domain/subscription_instance_transform.py,sha256=j_d49dFcSss0dl-BHS-ev2faLbE0y8hLvCfrzui6C74,4360
|
|
@@ -165,7 +165,7 @@ orchestrator/graphql/extensions/model_cache.py,sha256=1uhMRjBs9eK7zJ1Y6P6BopX068
|
|
|
165
165
|
orchestrator/graphql/extensions/stats.py,sha256=pGhEBQg45XvqZhRobcrCSGwt5AGmR3gflsm1dYiIg5g,2018
|
|
166
166
|
orchestrator/graphql/loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
167
167
|
orchestrator/graphql/loaders/subscriptions.py,sha256=31zE2WC7z-tPIUmVpU1QWOJvNbLvF7sYgY7JAQ6OPJg,1856
|
|
168
|
-
orchestrator/graphql/mutations/customer_description.py,sha256=
|
|
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
|
|
171
171
|
orchestrator/graphql/resolvers/customer.py,sha256=tq06MtMoaqFwqn3YQvSv0VmROW7QJZRJp1ykO4tUhck,934
|
|
@@ -205,7 +205,7 @@ orchestrator/graphql/utils/to_graphql_result_page.py,sha256=8ObkJP8reVf-TQOQVPKv
|
|
|
205
205
|
orchestrator/migrations/README,sha256=heMzebYwlGhnE8_4CWJ4LS74WoEZjBy-S-mIJRxAEKI,39
|
|
206
206
|
orchestrator/migrations/alembic.ini,sha256=kMoADqhGeubU8xanILNaqm4oixLy9m4ngYtdGpZcc7I,873
|
|
207
207
|
orchestrator/migrations/env.py,sha256=M_cPoAL2axuuup5fvMy8I_WTPHEw0RbPEHkhZ3QEGoE,3740
|
|
208
|
-
orchestrator/migrations/helpers.py,sha256=
|
|
208
|
+
orchestrator/migrations/helpers.py,sha256=xwi1Z-0MMZJ1Bk-HXkb6f_RU7BmO3ajK5a4qqO94elc,44068
|
|
209
209
|
orchestrator/migrations/script.py.mako,sha256=607Zrgp-Z-m9WGLt4wewN1QDOmHeifxcePUdADkSZyM,510
|
|
210
210
|
orchestrator/migrations/templates/alembic.ini.j2,sha256=jA-QykVparwWSNt5XDP0Zk7epLOhK7D87Af-i2shJV4,905
|
|
211
211
|
orchestrator/migrations/templates/env.py.j2,sha256=RfLAQItZ56Jlzwi6LJfBo92m1-th_bdfkFKD1mwTZIE,2821
|
|
@@ -231,15 +231,17 @@ orchestrator/migrations/versions/schema/2024-09-27_460ec6748e37_add_uuid_search_
|
|
|
231
231
|
orchestrator/migrations/versions/schema/2025-01-08_4c5859620539_add_version_column_to_subscription.py,sha256=xAhe74U0ZiVRo9Z8Uq7491RBbATMMUnYpTBjbG-BYL0,1690
|
|
232
232
|
orchestrator/migrations/versions/schema/2025-01-19_4fjdn13f83ga_add_validate_product_type_task.py,sha256=O0GfCISIDnyohGf3Ot_2HKedGRbMqLVox6t7Wd3PMvo,894
|
|
233
233
|
orchestrator/migrations/versions/schema/2025-02-12_bac6be6f2b4f_added_input_state_table.py,sha256=RZpLkWP1yekeZ68feO5v4LZYluKvnnIKRNDCE4tI9HM,1753
|
|
234
|
+
orchestrator/migrations/versions/schema/2025-02-20_68d14db1b8da_make_workflow_description_mandatory.py,sha256=uh5J2bR_UERqlNrDjDBSfiAdEfI9YQzgR9-t9ordFOo,847
|
|
234
235
|
orchestrator/migrations/versions/schema/2025-03-06_42b3d076a85b_subscription_instance_as_json_function.py,sha256=jtwDFOh-NlE31aH5dFmbynb23TZN6Mkzevxx-KLP7KE,776
|
|
235
236
|
orchestrator/migrations/versions/schema/2025-03-06_42b3d076a85b_subscription_instance_as_json_function.sql,sha256=hPldk0DAesUbHv3Qd_N7U-cAk-t1wIgxt4FOA120gQ8,1776
|
|
236
237
|
orchestrator/migrations/versions/schema/2025-04-09_fc5c993a4b4a_add_cascade_constraint_on_processes_.py,sha256=6kHRNSZxUze2jy7b8uRvkt5mzsax10Z-Z3lsACtPLRM,1067
|
|
238
|
+
orchestrator/migrations/versions/schema/2025-05-08_161918133bec_add_is_task_to_workflow.py,sha256=VLFDHFYRWn5ktUba0KuSPWyvjYJdfN1WypWmOPqIW18,721
|
|
237
239
|
orchestrator/schedules/__init__.py,sha256=JnnaglfK1qYUBKI6Dd9taV-tCZIPlAdAkHtnkJDMXxY,1066
|
|
238
240
|
orchestrator/schedules/resume_workflows.py,sha256=kSotzTAXjX7p9fpSYiGOpuxuTQfv54eRFAe0YSG0DHc,832
|
|
239
241
|
orchestrator/schedules/scheduling.py,sha256=ehtwgpbvMOk1jhn-hHgVzg_9wLJkI6l3mRY3DcO9ZVY,1526
|
|
240
242
|
orchestrator/schedules/task_vacuum.py,sha256=eovnuKimU8SFRw1IF62MsAVFSdgeeV1u57kapUbz8As,821
|
|
241
243
|
orchestrator/schedules/validate_products.py,sha256=YMr7ASSqdXM6pd6oZu0kr8mfmH8If16MzprrsHdN_ZU,1234
|
|
242
|
-
orchestrator/schedules/validate_subscriptions.py,sha256=
|
|
244
|
+
orchestrator/schedules/validate_subscriptions.py,sha256=9SYvsn4BJ5yo_1nu555hWjl5XffTx7QMaRhH5oOjM9E,2042
|
|
243
245
|
orchestrator/schemas/__init__.py,sha256=YDyZ0YBvzB4ML9oDBCBPGnBvf680zFFgUzg7X0tYBRY,2326
|
|
244
246
|
orchestrator/schemas/base.py,sha256=Vc444LetsINLRhG2SxW9Bq01hOzChPOhQWCImQTr-As,930
|
|
245
247
|
orchestrator/schemas/engine_settings.py,sha256=LF8al7tJssiilb5A4emPtUYo0tVDSaT1Lvo_DN_ttrY,1296
|
|
@@ -251,21 +253,21 @@ orchestrator/schemas/product_block.py,sha256=kCqvm6qadHpegMr9aWI_fYX-T7mS-5S-ldP
|
|
|
251
253
|
orchestrator/schemas/resource_type.py,sha256=VDju4XywcDDLxdpbWU62RTvR9QF8x_GRrpTlN_NE8uI,1064
|
|
252
254
|
orchestrator/schemas/subscription.py,sha256=-jXyHZIed9Xlia18ksSDyenblNN6Q2yM2FlGELyJ458,3423
|
|
253
255
|
orchestrator/schemas/subscription_descriptions.py,sha256=Ft_jw1U0bf9Z0U8O4OWfLlcl0mXCVT_qYVagBP3GbIQ,1262
|
|
254
|
-
orchestrator/schemas/workflow.py,sha256=
|
|
256
|
+
orchestrator/schemas/workflow.py,sha256=gBpLXttgU3cSkVyEqr5ji4yBskl-n7QNmEerUr9UXt0,2003
|
|
255
257
|
orchestrator/services/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
|
|
256
|
-
orchestrator/services/celery.py,sha256=
|
|
258
|
+
orchestrator/services/celery.py,sha256=ezw7IxkIZbmaRJt-9_Iwvn86TJV3Y3DTHI7Qjh0-r9s,5075
|
|
257
259
|
orchestrator/services/fixed_inputs.py,sha256=kyz7s2HLzyDulvcq-ZqefTw1om86COvyvTjz0_5CmgI,876
|
|
258
260
|
orchestrator/services/input_state.py,sha256=HF7wl9fWdaAW8pdCCqbuYoKyNj8dY0g8Ff8vXis8z5A,2211
|
|
259
261
|
orchestrator/services/process_broadcast_thread.py,sha256=D44YbjF8mRqGuznkRUV4SoRn1J0lfy_x1H508GnSVlU,4649
|
|
260
|
-
orchestrator/services/processes.py,sha256=
|
|
262
|
+
orchestrator/services/processes.py,sha256=rTH6zLNsun3qDCPguz2LYS87MQR_LJREIPrgkGS6kwk,30494
|
|
261
263
|
orchestrator/services/products.py,sha256=BP4KyE8zO-8z7Trrs5T6zKBOw53S9BfBJnHWI3p6u5Y,1943
|
|
262
264
|
orchestrator/services/resource_types.py,sha256=_QBy_JOW_X3aSTqH0CuLrq4zBJL0p7Q-UDJUcuK2_qc,884
|
|
263
265
|
orchestrator/services/settings.py,sha256=u-834F4KWloXS8zi7R9mp-D3cjl-rbVjKJRU35IqhXo,2723
|
|
264
266
|
orchestrator/services/subscription_relations.py,sha256=9C126TUfFvyBe7y4x007kH_dvxJ9pZ1zSnaWeH6HC5k,12261
|
|
265
|
-
orchestrator/services/subscriptions.py,sha256=
|
|
267
|
+
orchestrator/services/subscriptions.py,sha256=nr2HI89nC0lYjzTh2j-lEQ5cPQK43LNZv3gvP6jbepw,27189
|
|
266
268
|
orchestrator/services/tasks.py,sha256=NjPkuauQoh9UJDcjA7OcKFgPk0i6NoKdDO7HlpGbBJ8,6575
|
|
267
269
|
orchestrator/services/translations.py,sha256=GyP8soUFGej8AS8uulBsk10CCK6Kwfjv9AHMFm3ElQY,1713
|
|
268
|
-
orchestrator/services/workflows.py,sha256=
|
|
270
|
+
orchestrator/services/workflows.py,sha256=iEkt2OBuTwkDru4V6ZSKatnw0b96ZdPV-VQqeZ9EOgU,4015
|
|
269
271
|
orchestrator/utils/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
|
|
270
272
|
orchestrator/utils/crypt.py,sha256=18eNamYWMllPkxyRtWIde3FDr3rSF74R5SAL6WsCj9Y,5584
|
|
271
273
|
orchestrator/utils/datetime.py,sha256=a1WQ_yvu7MA0TiaRpC5avwbOSFdrj4eMrV4a7I2sD5Q,1477
|
|
@@ -275,11 +277,11 @@ orchestrator/utils/enrich_process.py,sha256=o_QSy5Q4wn1SMHhzVOw6bp7uhDXr7GhAIWRD
|
|
|
275
277
|
orchestrator/utils/errors.py,sha256=6FxvXrITmRjP5bYnJJ3CxjAwA5meNjRAVYouz4TWKkU,4653
|
|
276
278
|
orchestrator/utils/fixed_inputs.py,sha256=pnL6I_19VMp_Bny8SYjSzVFNvTFDyeCxFFOWGhTnDiQ,2665
|
|
277
279
|
orchestrator/utils/functional.py,sha256=X1MDNwHmkU3-8mFb21m31HGlcfc5TygliXR0sXN3-rU,8304
|
|
278
|
-
orchestrator/utils/get_subscription_dict.py,sha256=
|
|
280
|
+
orchestrator/utils/get_subscription_dict.py,sha256=hctkFvD3U6LpygNwz2uesRMdnXSY-PaohBqPATsi9r4,694
|
|
279
281
|
orchestrator/utils/get_updated_properties.py,sha256=egVZ0R5LNJ4e51Z8SXlU8cmb4tXxG-xb1d7OKwh-7xI,1322
|
|
280
282
|
orchestrator/utils/helpers.py,sha256=NjUF3IvWdnLulliP8-JQvGGGpHrh0vs0Vm092ynw-ss,3212
|
|
281
283
|
orchestrator/utils/json.py,sha256=7386sdqkrKYyy4sbn5NscwctH_v1hLyw5172P__rU3g,8341
|
|
282
|
-
orchestrator/utils/redis.py,sha256=
|
|
284
|
+
orchestrator/utils/redis.py,sha256=BjUNmrKx8YVyJIucl2mhXubK6WV-49OnAU6rPMOZpM0,4469
|
|
283
285
|
orchestrator/utils/redis_client.py,sha256=9rhsvedjK_CyClAjUicQyge0mVIViATqKFGZyjBY3XA,1384
|
|
284
286
|
orchestrator/utils/search_query.py,sha256=ji5LHtrzohGz6b1IG41cnPdpWXzLEzz4SGWgHly_yfU,16205
|
|
285
287
|
orchestrator/utils/state.py,sha256=RYKVlvKDBfsBdDk9wHjZKBTlQJbV4SqtCotAlTA2-bI,14021
|
|
@@ -290,17 +292,17 @@ orchestrator/websocket/websocket_manager.py,sha256=hwlG9FDXcNU42jDNNsPMQLIyrvEpG
|
|
|
290
292
|
orchestrator/websocket/managers/broadcast_websocket_manager.py,sha256=fwoSgTjkHJ2GmsLTU9dqQpAA9i8b1McPu7gLNzxtfG4,5401
|
|
291
293
|
orchestrator/websocket/managers/memory_websocket_manager.py,sha256=lF5EEx1iFMCGEkTbItTDr88NENMSaSeG1QrJ7teoPkY,3324
|
|
292
294
|
orchestrator/workflows/__init__.py,sha256=NzIGGI-8SNAwCk2YqH6sHhEWbgAY457ntDwjO15N8v4,4131
|
|
293
|
-
orchestrator/workflows/modify_note.py,sha256=
|
|
295
|
+
orchestrator/workflows/modify_note.py,sha256=l6QtijRPv8gnHxzwTz_4nWIPcZ0FcKQh_yFbtjYEDMg,2163
|
|
294
296
|
orchestrator/workflows/removed_workflow.py,sha256=V0Da5TEdfLdZZKD38ig-MTp3_IuE7VGqzHHzvPYQmLI,909
|
|
295
|
-
orchestrator/workflows/steps.py,sha256=
|
|
296
|
-
orchestrator/workflows/utils.py,sha256=
|
|
297
|
+
orchestrator/workflows/steps.py,sha256=ulpheoHaCOE1qh71Bja4KW4pItQh1Z6q4QU4tn5GtNk,6067
|
|
298
|
+
orchestrator/workflows/utils.py,sha256=yBwfITlseimyLEzbwI0ehOAlr-xI1N3WGVudFz4boXk,13778
|
|
297
299
|
orchestrator/workflows/tasks/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
|
|
298
300
|
orchestrator/workflows/tasks/cleanup_tasks_log.py,sha256=BfWYbPXhnLAHUJ0mlODDnjZnQQAvKCZJDVTwbwOWI04,1624
|
|
299
301
|
orchestrator/workflows/tasks/resume_workflows.py,sha256=MzJqlSXUvKStkT7NGzxZyRlfAer_ezYm-kjUqaZi0yc,2359
|
|
300
|
-
orchestrator/workflows/tasks/validate_product_type.py,sha256=
|
|
301
|
-
orchestrator/workflows/tasks/validate_products.py,sha256=
|
|
302
|
+
orchestrator/workflows/tasks/validate_product_type.py,sha256=paG-NAY1bdde3Adt8zItkcBKf5Pxw6f5ngGW6an6dYU,3192
|
|
303
|
+
orchestrator/workflows/tasks/validate_products.py,sha256=GZJBoFF-WMphS7ghMs2-gqvV2iL1F0POhk0uSNt93n0,8510
|
|
302
304
|
orchestrator/workflows/translations/en-GB.json,sha256=ST53HxkphFLTMjFHonykDBOZ7-P_KxksktZU3GbxLt0,846
|
|
303
|
-
orchestrator_core-
|
|
304
|
-
orchestrator_core-
|
|
305
|
-
orchestrator_core-
|
|
306
|
-
orchestrator_core-
|
|
305
|
+
orchestrator_core-4.0.0rc2.dist-info/licenses/LICENSE,sha256=b-aA5OZQuuBATmLKo_mln8CQrDPPhg3ghLzjPjLn4Tg,11409
|
|
306
|
+
orchestrator_core-4.0.0rc2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
307
|
+
orchestrator_core-4.0.0rc2.dist-info/METADATA,sha256=eEc0N4MXX03Q--Jx61bXgZqQ3zwjzjdwLUhVl_5eGFM,5032
|
|
308
|
+
orchestrator_core-4.0.0rc2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|