mageflow 0.3.2__tar.gz → 0.3.4__tar.gz
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.
- {mageflow-0.3.2 → mageflow-0.3.4}/PKG-INFO +8 -2
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/__init__.py +6 -6
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/callbacks.py +31 -12
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/chain/workflows.py +0 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/clients/hatchet/adapter.py +32 -17
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/clients/hatchet/mageflow.py +18 -12
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/clients/hatchet/workflow.py +0 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/config.py +10 -6
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/lifecycle/signature.py +0 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/lifecycle/task.py +0 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/swarm/workflows.py +0 -1
- mageflow-0.3.4/mageflow/testing/__init__.py +15 -0
- mageflow-0.3.4/mageflow/testing/_adapter.py +467 -0
- mageflow-0.3.4/mageflow/testing/_config.py +42 -0
- mageflow-0.3.4/mageflow/testing/_redis.py +23 -0
- mageflow-0.3.4/mageflow/testing/plugin.py +94 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/pyproject.toml +20 -2
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/models.py +19 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/signature/test_edge_case.py +25 -8
- mageflow-0.3.4/tests/integration/hatchet/test_retry_cache.py +65 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/test_ttl.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/worker.py +73 -6
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/assertions.py +0 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/callbacks/conftest.py +6 -4
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/callbacks/test_handle_task_callback.py +13 -19
- mageflow-0.3.4/tests/unit/callbacks/test_retry_cache.py +791 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/clients/test_hatchet_adapter.py +81 -5
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/test_remove_ttl.py +17 -3
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/test_ttl_config.py +13 -10
- mageflow-0.3.4/tests/unit/test_ttl_validation.py +48 -0
- mageflow-0.3.4/tests/unit/testing/conftest.py +22 -0
- mageflow-0.3.4/tests/unit/testing/test_chain_dispatch.py +169 -0
- mageflow-0.3.4/tests/unit/testing/test_integration_user_workflow.py +230 -0
- mageflow-0.3.4/tests/unit/testing/test_swarm_dispatch.py +138 -0
- mageflow-0.3.4/tests/unit/testing/test_task_dispatch.py +194 -0
- mageflow-0.3.4/tests/unit/workflows/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/workflows/test_chain_end.py +1 -4
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/workflows/test_swarm_item_failed.py +5 -16
- {mageflow-0.3.2 → mageflow-0.3.4}/.gitignore +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/chain/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/chain/messages.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/client.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/clients/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/clients/hatchet/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/clients/inner_task_names.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/lifecycle/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/startup.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/swarm/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/swarm/consts.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/swarm/messages.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/utils/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/utils/mageflow.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/mageflow/utils/pythonic.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/conftest.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/assertions.py +3 -3
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/chain/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/chain/test__chain.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/chain/test_edge_cases.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/chain/test_stop_resume.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/conftest.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/docker-compose.hatchet.yml +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/signature/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/signature/test__signature.py +2 -2
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/signature/test_stop_resume.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/swarm/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/swarm/test__swarm.py +2 -2
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/swarm/test_edge_cases.py +2 -2
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/swarm/test_stop_resume.py +2 -2
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/swarm/test_workflow.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/test_complex_scenarios.py +3 -3
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/hatchet/test_task_models.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/integration/test_redis_ttl.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/callbacks/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/clients/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/conftest.py +6 -6
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/idempotency/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/idempotency/conftest.py +4 -4
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/idempotency/test_chain_workflows_idempotent.py +3 -3
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/idempotency/test_fill_running_tasks_idempotent.py +3 -3
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/idempotency/test_fill_workflow_running_tasks_idempotent.py +3 -3
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/idempotency/test_swarm_item_done_idempotent.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/idempotency/test_swarm_item_failed_idempotent.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/race_condition/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/race_condition/test_fill_running_tasks.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/test_client.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/test_client_signature_compatibility.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/test_param_config.py +0 -0
- {mageflow-0.3.2/tests/unit/workflows → mageflow-0.3.4/tests/unit/testing}/__init__.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/utils.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/workflows/conftest.py +4 -4
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/workflows/test_chain_error.py +0 -0
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/workflows/test_fill_running_tasks.py +3 -3
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/workflows/test_fill_swarm_corrupted_callbacks.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/workflows/test_fill_swarm_running_tasks.py +2 -2
- {mageflow-0.3.2 → mageflow-0.3.4}/tests/unit/workflows/test_swarm_item_done.py +1 -1
- {mageflow-0.3.2 → mageflow-0.3.4}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mageflow
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Manage Graph Execution Flow - A unified interface for task orchestration across different task managers
|
|
5
5
|
Project-URL: Homepage, https://imaginary-cherry.github.io/mageflow/
|
|
6
6
|
Project-URL: Documentation, https://imaginary-cherry.github.io/mageflow/
|
|
@@ -26,7 +26,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
26
26
|
Classifier: Topic :: System :: Distributed Computing
|
|
27
27
|
Classifier: Typing :: Typed
|
|
28
28
|
Requires-Python: <3.14,>=3.10
|
|
29
|
-
Requires-Dist: thirdmagic<0.1.0,>=0.0.
|
|
29
|
+
Requires-Dist: thirdmagic<0.1.0,>=0.0.5
|
|
30
30
|
Provides-Extra: dev
|
|
31
31
|
Requires-Dist: black>=26.1.0; extra == 'dev'
|
|
32
32
|
Requires-Dist: coverage[toml]<8.0.0,>=7.0.0; extra == 'dev'
|
|
@@ -37,5 +37,11 @@ Requires-Dist: pytest-asyncio<2.0.0,>=1.2.0; extra == 'dev'
|
|
|
37
37
|
Requires-Dist: pytest<10.0.0,>=9.0.2; extra == 'dev'
|
|
38
38
|
Requires-Dist: requests<3.0.0,>=2.32.5; extra == 'dev'
|
|
39
39
|
Requires-Dist: ruff>=0.15.5; extra == 'dev'
|
|
40
|
+
Requires-Dist: testcontainers[redis]<5.0.0,>=4.14.0; extra == 'dev'
|
|
40
41
|
Provides-Extra: hatchet
|
|
41
42
|
Requires-Dist: hatchet-sdk<1.24.0,>=1.22.5; extra == 'hatchet'
|
|
43
|
+
Provides-Extra: testing
|
|
44
|
+
Requires-Dist: fakeredis[json,lua]<3.0.0,>=2.34.0; extra == 'testing'
|
|
45
|
+
Requires-Dist: pytest-asyncio<2.0.0,>=1.2.0; extra == 'testing'
|
|
46
|
+
Requires-Dist: pytest<10.0.0,>=9.0.0; extra == 'testing'
|
|
47
|
+
Requires-Dist: testcontainers[redis]<5.0.0,>=4.14.0; extra == 'testing'
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import rapyer
|
|
2
2
|
from rapyer.fields import RapyerKey
|
|
3
|
-
|
|
4
|
-
from mageflow.callbacks import handle_task_callback
|
|
5
|
-
from mageflow.client import Mageflow
|
|
6
|
-
from mageflow.config import MageflowConfig, SignatureTTLConfig, TTLConfig
|
|
7
|
-
from mageflow.startup import start_mageflow
|
|
3
|
+
from thirdmagic import abounded_field
|
|
8
4
|
from thirdmagic.chain.creator import chain as achain
|
|
9
5
|
from thirdmagic.signature import Signature
|
|
10
6
|
from thirdmagic.swarm.creator import swarm as aswarm
|
|
11
7
|
from thirdmagic.task import TaskSignature
|
|
12
8
|
from thirdmagic.task import sign as asign
|
|
13
9
|
|
|
10
|
+
from mageflow.callbacks import handle_task_callback
|
|
11
|
+
from mageflow.client import Mageflow
|
|
12
|
+
from mageflow.config import MageflowConfig, SignatureTTLConfig, TTLConfig
|
|
13
|
+
from mageflow.startup import start_mageflow
|
|
14
|
+
|
|
14
15
|
lock_task = TaskSignature.alock_from_key
|
|
15
16
|
resume = TaskSignature.resume_from_key
|
|
16
17
|
pause = TaskSignature.pause_from_key
|
|
@@ -22,7 +23,6 @@ async def load_sign(key: RapyerKey) -> Signature:
|
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
load_signature = rapyer.afind_one
|
|
25
|
-
abounded_field = rapyer.apipeline
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
__all__ = [
|
|
@@ -7,11 +7,16 @@ from typing import Any
|
|
|
7
7
|
from hatchet_sdk import Context
|
|
8
8
|
from hatchet_sdk.runnables.types import EmptyModel
|
|
9
9
|
from pydantic import BaseModel
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
from thirdmagic.signature.retry_cache import (
|
|
11
|
+
retry_cache_ctx,
|
|
12
|
+
setup_retry_cache,
|
|
13
|
+
teardown_retry_cache,
|
|
14
|
+
)
|
|
12
15
|
from thirdmagic.task.model import TaskSignature
|
|
13
16
|
from thirdmagic.task_def import MageflowTaskDefinition
|
|
14
17
|
|
|
18
|
+
from mageflow.utils.pythonic import flexible_call
|
|
19
|
+
|
|
15
20
|
|
|
16
21
|
class AcceptParams(Enum):
|
|
17
22
|
JUST_MESSAGE = 1
|
|
@@ -27,6 +32,7 @@ def handle_task_callback(
|
|
|
27
32
|
expected_params: AcceptParams = AcceptParams.NO_CTX,
|
|
28
33
|
wrap_res: bool = True,
|
|
29
34
|
send_signature: bool = False,
|
|
35
|
+
is_idempotent: bool = False,
|
|
30
36
|
):
|
|
31
37
|
def task_decorator(func):
|
|
32
38
|
@functools.wraps(func)
|
|
@@ -40,8 +46,18 @@ def handle_task_callback(
|
|
|
40
46
|
# NOTE: This should not run, the task should cancel, but just in case
|
|
41
47
|
return {"Error": "Task should have been canceled"}
|
|
42
48
|
is_normal_run = lifecycle.is_vanilla_run()
|
|
49
|
+
is_task_finish = False
|
|
43
50
|
signature = await lifecycle.start_task()
|
|
44
51
|
|
|
52
|
+
# Setup retry cache for signature idempotency on retries (durable tasks only)
|
|
53
|
+
cache_token = None
|
|
54
|
+
cache_state = None
|
|
55
|
+
if is_idempotent:
|
|
56
|
+
cache_state = await setup_retry_cache(
|
|
57
|
+
ctx.workflow_id, ctx.attempt_number
|
|
58
|
+
)
|
|
59
|
+
cache_token = retry_cache_ctx.set(cache_state)
|
|
60
|
+
|
|
45
61
|
# Add params if user requires
|
|
46
62
|
if send_signature:
|
|
47
63
|
kwargs["signature"] = signature
|
|
@@ -53,20 +69,18 @@ def handle_task_callback(
|
|
|
53
69
|
result = await flexible_call(func, message, *args, **kwargs)
|
|
54
70
|
else:
|
|
55
71
|
result = await flexible_call(func, message, ctx, *args, **kwargs)
|
|
56
|
-
except asyncio.CancelledError as e:
|
|
57
|
-
|
|
58
|
-
await lifecycle.task_failed(msg_data, e)
|
|
59
|
-
raise
|
|
60
|
-
except Exception as e:
|
|
61
|
-
if is_normal_run:
|
|
62
|
-
raise
|
|
63
|
-
if not TaskSignature.ClientAdapter.should_task_retry(
|
|
72
|
+
except (Exception, asyncio.CancelledError) as e:
|
|
73
|
+
will_retry = TaskSignature.ClientAdapter.should_task_retry(
|
|
64
74
|
task_model, ctx.attempt_number, e
|
|
65
|
-
)
|
|
66
|
-
|
|
75
|
+
)
|
|
76
|
+
if not will_retry:
|
|
77
|
+
is_task_finish = True
|
|
78
|
+
if not is_normal_run:
|
|
79
|
+
await lifecycle.task_failed(msg_data, e)
|
|
67
80
|
raise
|
|
68
81
|
else:
|
|
69
82
|
# If this is a simple task, no signature, then we dont do any manipulation
|
|
83
|
+
is_task_finish = True
|
|
70
84
|
if is_normal_run:
|
|
71
85
|
return result
|
|
72
86
|
task_results = HatchetResult(hatchet_results=result)
|
|
@@ -76,6 +90,11 @@ def handle_task_callback(
|
|
|
76
90
|
return task_results
|
|
77
91
|
else:
|
|
78
92
|
return result
|
|
93
|
+
finally:
|
|
94
|
+
if cache_token is not None:
|
|
95
|
+
retry_cache_ctx.reset(cache_token)
|
|
96
|
+
if is_task_finish and cache_state:
|
|
97
|
+
await teardown_retry_cache(cache_state)
|
|
79
98
|
|
|
80
99
|
wrapper.__signature__ = inspect.signature(func)
|
|
81
100
|
return wrapper
|
|
@@ -8,6 +8,13 @@ from hatchet_sdk.runnables.types import EmptyModel
|
|
|
8
8
|
from hatchet_sdk.runnables.workflow import BaseWorkflow
|
|
9
9
|
from pydantic import BaseModel, TypeAdapter
|
|
10
10
|
from rapyer.fields import RapyerKey
|
|
11
|
+
from thirdmagic.chain import ChainTaskSignature
|
|
12
|
+
from thirdmagic.clients.base import BaseClientAdapter
|
|
13
|
+
from thirdmagic.consts import TASK_ID_PARAM_NAME
|
|
14
|
+
from thirdmagic.signature import Signature
|
|
15
|
+
from thirdmagic.swarm import SwarmTaskSignature
|
|
16
|
+
from thirdmagic.task import TaskSignature
|
|
17
|
+
from thirdmagic.task_def import MageflowTaskDefinition
|
|
11
18
|
|
|
12
19
|
from mageflow.chain.messages import ChainCallbackMessage, ChainErrorMessage
|
|
13
20
|
from mageflow.clients.hatchet.workflow import MageflowWorkflow
|
|
@@ -25,13 +32,6 @@ from mageflow.swarm.messages import (
|
|
|
25
32
|
SwarmErrorMessage,
|
|
26
33
|
SwarmResultsMessage,
|
|
27
34
|
)
|
|
28
|
-
from thirdmagic.chain import ChainTaskSignature
|
|
29
|
-
from thirdmagic.clients.base import BaseClientAdapter
|
|
30
|
-
from thirdmagic.consts import TASK_ID_PARAM_NAME
|
|
31
|
-
from thirdmagic.signature import Signature
|
|
32
|
-
from thirdmagic.swarm import SwarmTaskSignature
|
|
33
|
-
from thirdmagic.task import TaskSignature
|
|
34
|
-
from thirdmagic.task_def import MageflowTaskDefinition
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
class HatchetClientAdapter(BaseClientAdapter):
|
|
@@ -123,6 +123,15 @@ class HatchetClientAdapter(BaseClientAdapter):
|
|
|
123
123
|
def extract_retries(self, client_task: BaseWorkflow) -> int:
|
|
124
124
|
return client_task.tasks[0].retries
|
|
125
125
|
|
|
126
|
+
def _prepare_wf(self, signature: TaskSignature, set_return_field: bool, **kwargs):
|
|
127
|
+
total_kwargs = signature.kwargs | kwargs
|
|
128
|
+
workflow = self.hatchet.workflow(
|
|
129
|
+
name=signature.task_name, input_validator=signature.model_validators
|
|
130
|
+
)
|
|
131
|
+
return_field_name = signature.return_field_name if set_return_field else None
|
|
132
|
+
mageflow_wf = MageflowWorkflow(workflow, total_kwargs, return_field_name)
|
|
133
|
+
return mageflow_wf
|
|
134
|
+
|
|
126
135
|
async def acall_signature(
|
|
127
136
|
self,
|
|
128
137
|
signature: TaskSignature,
|
|
@@ -134,17 +143,23 @@ class HatchetClientAdapter(BaseClientAdapter):
|
|
|
134
143
|
if msg is None:
|
|
135
144
|
msg = EmptyModel()
|
|
136
145
|
options = self._update_options(signature, options)
|
|
137
|
-
|
|
138
|
-
workflow = self.hatchet.workflow(
|
|
139
|
-
name=signature.task_name, input_validator=signature.model_validators
|
|
140
|
-
)
|
|
141
|
-
mageflow_wf = MageflowWorkflow(
|
|
142
|
-
workflow,
|
|
143
|
-
total_kwargs,
|
|
144
|
-
signature.return_field_name if set_return_field else None,
|
|
145
|
-
)
|
|
146
|
+
mageflow_wf = self._prepare_wf(signature, set_return_field, **kwargs)
|
|
146
147
|
return await mageflow_wf.aio_run_no_wait(msg, options)
|
|
147
148
|
|
|
149
|
+
async def await_signature(
|
|
150
|
+
self,
|
|
151
|
+
signature: "TaskSignature",
|
|
152
|
+
msg: Any,
|
|
153
|
+
set_return_field: bool,
|
|
154
|
+
options: TriggerWorkflowOptions = None,
|
|
155
|
+
**kwargs,
|
|
156
|
+
):
|
|
157
|
+
if msg is None:
|
|
158
|
+
msg = EmptyModel()
|
|
159
|
+
options = self._update_options(signature, options)
|
|
160
|
+
mageflow_wf = self._prepare_wf(signature, set_return_field, **kwargs)
|
|
161
|
+
return await mageflow_wf.aio_run(msg, options)
|
|
162
|
+
|
|
148
163
|
def should_task_retry(
|
|
149
164
|
self,
|
|
150
165
|
task_definition: MageflowTaskDefinition,
|
|
@@ -153,7 +168,7 @@ class HatchetClientAdapter(BaseClientAdapter):
|
|
|
153
168
|
) -> bool:
|
|
154
169
|
finish_retry = (
|
|
155
170
|
task_definition.retries is not None
|
|
156
|
-
and attempt_num
|
|
171
|
+
and attempt_num <= task_definition.retries
|
|
157
172
|
)
|
|
158
173
|
return finish_retry and not isinstance(e, NonRetryableException)
|
|
159
174
|
|
|
@@ -17,6 +17,14 @@ from hatchet_sdk.runnables.types import (
|
|
|
17
17
|
from hatchet_sdk.runnables.workflow import BaseWorkflow, Standalone
|
|
18
18
|
from hatchet_sdk.worker.worker import LifespanFn
|
|
19
19
|
from redis.asyncio import Redis
|
|
20
|
+
from thirdmagic import chain, sign
|
|
21
|
+
from thirdmagic.chain import ChainTaskSignature
|
|
22
|
+
from thirdmagic.signature import Signature
|
|
23
|
+
from thirdmagic.swarm import SwarmTaskSignature
|
|
24
|
+
from thirdmagic.swarm.creator import SignatureOptions, swarm
|
|
25
|
+
from thirdmagic.task import TaskInputType, TaskSignature, TaskSignatureConvertible
|
|
26
|
+
from thirdmagic.task_def import MageflowTaskDefinition
|
|
27
|
+
from thirdmagic.utils import HatchetTaskType
|
|
20
28
|
from typing_extensions import override
|
|
21
29
|
|
|
22
30
|
from mageflow.callbacks import AcceptParams, handle_task_callback
|
|
@@ -47,14 +55,6 @@ from mageflow.swarm.workflows import (
|
|
|
47
55
|
swarm_item_failed,
|
|
48
56
|
)
|
|
49
57
|
from mageflow.utils.mageflow import does_task_wants_ctx
|
|
50
|
-
from thirdmagic import chain, sign
|
|
51
|
-
from thirdmagic.chain import ChainTaskSignature
|
|
52
|
-
from thirdmagic.signature import Signature
|
|
53
|
-
from thirdmagic.swarm import SwarmTaskSignature
|
|
54
|
-
from thirdmagic.swarm.creator import SignatureOptions, swarm
|
|
55
|
-
from thirdmagic.task import TaskInputType, TaskSignature, TaskSignatureConvertible
|
|
56
|
-
from thirdmagic.task_def import MageflowTaskDefinition
|
|
57
|
-
from thirdmagic.utils import HatchetTaskType
|
|
58
58
|
|
|
59
59
|
Duration = timedelta | str
|
|
60
60
|
|
|
@@ -125,14 +125,16 @@ class HatchetMageflow(Hatchet):
|
|
|
125
125
|
)
|
|
126
126
|
)
|
|
127
127
|
|
|
128
|
-
def task_decorator(self, func: Callable, hatchet_task):
|
|
128
|
+
def task_decorator(self, func: Callable, hatchet_task, is_idempotent: bool = False):
|
|
129
129
|
param_config = (
|
|
130
130
|
AcceptParams.ALL
|
|
131
131
|
if does_task_wants_ctx(func)
|
|
132
132
|
else self.mageflow_config.param_config
|
|
133
133
|
)
|
|
134
134
|
send_signature = getattr(func, "__send_signature__", False)
|
|
135
|
-
handler_dec = handle_task_callback(
|
|
135
|
+
handler_dec = handle_task_callback(
|
|
136
|
+
param_config, send_signature=send_signature, is_idempotent=is_idempotent
|
|
137
|
+
)
|
|
136
138
|
func = handler_dec(func)
|
|
137
139
|
wf = hatchet_task(func)
|
|
138
140
|
self._add_task_def(wf)
|
|
@@ -146,7 +148,9 @@ class HatchetMageflow(Hatchet):
|
|
|
146
148
|
"""
|
|
147
149
|
hatchet_task = super().task(name=name, **kwargs)
|
|
148
150
|
|
|
149
|
-
decorator = functools.partial(
|
|
151
|
+
decorator = functools.partial(
|
|
152
|
+
self.task_decorator, hatchet_task=hatchet_task, is_idempotent=False
|
|
153
|
+
)
|
|
150
154
|
return decorator
|
|
151
155
|
|
|
152
156
|
@override
|
|
@@ -156,7 +160,9 @@ class HatchetMageflow(Hatchet):
|
|
|
156
160
|
"""
|
|
157
161
|
hatchet_task = super().durable_task(name=name, **kwargs)
|
|
158
162
|
|
|
159
|
-
decorator = functools.partial(
|
|
163
|
+
decorator = functools.partial(
|
|
164
|
+
self.task_decorator, hatchet_task=hatchet_task, is_idempotent=True
|
|
165
|
+
)
|
|
160
166
|
|
|
161
167
|
return decorator
|
|
162
168
|
|
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import dataclasses
|
|
2
|
-
from dataclasses import
|
|
2
|
+
from dataclasses import field
|
|
3
3
|
from typing import Optional
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
from pydantic.dataclasses import dataclass
|
|
6
7
|
from thirdmagic.chain import ChainTaskSignature
|
|
7
8
|
from thirdmagic.consts import REMOVED_TASK_TTL
|
|
8
|
-
from thirdmagic.signature import SignatureConfig
|
|
9
|
+
from thirdmagic.signature import Signature, SignatureConfig
|
|
9
10
|
from thirdmagic.swarm import SwarmTaskSignature
|
|
10
11
|
from thirdmagic.swarm.state import PublishState
|
|
11
12
|
from thirdmagic.task import TaskSignature
|
|
12
13
|
|
|
14
|
+
from mageflow.callbacks import AcceptParams
|
|
15
|
+
|
|
13
16
|
|
|
14
17
|
@dataclass
|
|
15
18
|
class SignatureTTLConfig:
|
|
16
19
|
active_ttl: Optional[int] = None # seconds, None = use general
|
|
17
|
-
ttl_when_sign_done: Optional[int] = None
|
|
20
|
+
ttl_when_sign_done: Optional[int] = Field(default=None, ge=REMOVED_TASK_TTL)
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
@dataclass
|
|
21
24
|
class TTLConfig:
|
|
22
25
|
active_ttl: int = 24 * 60 * 60 # general active TTL (default 24h)
|
|
23
|
-
ttl_when_sign_done: int =
|
|
26
|
+
ttl_when_sign_done: int = Field(default=REMOVED_TASK_TTL, ge=REMOVED_TASK_TTL)
|
|
24
27
|
task: SignatureTTLConfig = field(default_factory=SignatureTTLConfig)
|
|
25
28
|
chain: SignatureTTLConfig = field(default_factory=SignatureTTLConfig)
|
|
26
29
|
swarm: SignatureTTLConfig = field(default_factory=SignatureTTLConfig)
|
|
@@ -44,4 +47,5 @@ def apply_ttl_config(ttl_config: TTLConfig):
|
|
|
44
47
|
done_ttl = sig_config.ttl_when_sign_done or ttl_config.ttl_when_sign_done
|
|
45
48
|
|
|
46
49
|
sig_type.Meta = dataclasses.replace(sig_type.Meta, ttl=active_ttl)
|
|
47
|
-
sig_type
|
|
50
|
+
if issubclass(sig_type, Signature):
|
|
51
|
+
sig_type.SignatureSettings = SignatureConfig(ttl_when_sign_done=done_ttl)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from mageflow.testing._adapter import (
|
|
2
|
+
ChainDispatchRecord,
|
|
3
|
+
RecordedDispatch,
|
|
4
|
+
SwarmDispatchRecord,
|
|
5
|
+
TaskDispatchRecord,
|
|
6
|
+
TestClientAdapter,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"TestClientAdapter",
|
|
11
|
+
"RecordedDispatch",
|
|
12
|
+
"TaskDispatchRecord",
|
|
13
|
+
"SwarmDispatchRecord",
|
|
14
|
+
"ChainDispatchRecord",
|
|
15
|
+
]
|