dex-python-sdk 0.0.1__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.
- dex/__init__.py +14 -0
- dex/client.py +568 -0
- dex/client_options.py +34 -0
- dex/command_request.py +130 -0
- dex/command_results.py +116 -0
- dex/communication.py +141 -0
- dex/communication_schema.py +68 -0
- dex/data_attributes.py +75 -0
- dex/dexpb/__init__.py +1 -0
- dex/dexpb/dex_pb2.py +305 -0
- dex/dexpb/dex_pb2.pyi +1273 -0
- dex/dexpb/dex_pb2_grpc.py +1126 -0
- dex/errors.py +132 -0
- dex/object_encoder.py +818 -0
- dex/persistence.py +94 -0
- dex/persistence_options.py +24 -0
- dex/persistence_schema.py +58 -0
- dex/py.typed +1 -0
- dex/registry.py +209 -0
- dex/reset_workflow_type_and_options.py +77 -0
- dex/rpc.py +100 -0
- dex/search_attributes.py +189 -0
- dex/state_decision.py +161 -0
- dex/state_execution_locals.py +71 -0
- dex/state_movement.py +123 -0
- dex/state_schema.py +54 -0
- dex/stop_workflow_options.py +23 -0
- dex/tests/__init__.py +84 -0
- dex/tests/dex-service-env/.env +7 -0
- dex/tests/dex-service-env/docker-compose-init.sh +44 -0
- dex/tests/dex-service-env/docker-compose.yml +87 -0
- dex/tests/dex-service-env/dynamicconfig/README.md +39 -0
- dex/tests/dex-service-env/dynamicconfig/development-sql.yaml +6 -0
- dex/tests/dex-service-env/dynamicconfig/docker.yaml +0 -0
- dex/tests/test_abnormal_exit_workflow.py +48 -0
- dex/tests/test_basic_workflow.py +75 -0
- dex/tests/test_conditional_complete.py +56 -0
- dex/tests/test_describe_workflow.py +45 -0
- dex/tests/test_empty_data_decodes_properly.py +79 -0
- dex/tests/test_internal_channel.py +33 -0
- dex/tests/test_internal_channel_with_no_prefix_channel.py +46 -0
- dex/tests/test_persistence_data_attributes.py +67 -0
- dex/tests/test_persistence_search_attributes.py +132 -0
- dex/tests/test_persistence_state_execution_locals.py +43 -0
- dex/tests/test_rpc.py +69 -0
- dex/tests/test_rpc_with_memo.py +200 -0
- dex/tests/test_rpc_with_memo_duplicate_java_tests.py +122 -0
- dex/tests/test_signal.py +56 -0
- dex/tests/test_skip_wait_until.py +85 -0
- dex/tests/test_state_failure_recovery.py +33 -0
- dex/tests/test_timer.py +40 -0
- dex/tests/test_wait_for_state_execution_completion.py +58 -0
- dex/tests/test_workflow_errors.py +92 -0
- dex/tests/test_workflow_state_options.py +123 -0
- dex/tests/test_workflow_state_options_override.py +49 -0
- dex/tests/worker_server.py +74 -0
- dex/tests/workflows/abnormal_exit_workflow.py +48 -0
- dex/tests/workflows/basic_workflow.py +69 -0
- dex/tests/workflows/conditional_complete_workflow.py +101 -0
- dex/tests/workflows/describe_workflow.py +52 -0
- dex/tests/workflows/empty_data_workflow.py +51 -0
- dex/tests/workflows/internal_channel_workflow.py +137 -0
- dex/tests/workflows/internal_channel_workflow_with_no_prefix_channel.py +108 -0
- dex/tests/workflows/java_duplicate_rpc_memo_workflow.py +285 -0
- dex/tests/workflows/persistence_data_attributes_workflow.py +104 -0
- dex/tests/workflows/persistence_search_attributes_workflow.py +167 -0
- dex/tests/workflows/persistence_state_execution_local_workflow.py +69 -0
- dex/tests/workflows/recovery_workflow.py +90 -0
- dex/tests/workflows/rpc_memo_workflow.py +238 -0
- dex/tests/workflows/rpc_workflow.py +125 -0
- dex/tests/workflows/state_options_override_workflow.py +100 -0
- dex/tests/workflows/state_options_workflow.py +92 -0
- dex/tests/workflows/timer_workflow.py +52 -0
- dex/tests/workflows/wait_for_state_with_state_execution_id_workflow.py +77 -0
- dex/tests/workflows/wait_for_state_with_wait_for_key_workflow.py +78 -0
- dex/tests/workflows/wait_internal_channel_workflow.py +53 -0
- dex/tests/workflows/wait_signal_workflow.py +154 -0
- dex/type_store.py +105 -0
- dex/unregistered_client.py +595 -0
- dex/utils/__init__.py +14 -0
- dex/utils/dex_typing.py +31 -0
- dex/utils/persistence_utils.py +37 -0
- dex/worker_service.py +441 -0
- dex/workflow.py +86 -0
- dex/workflow_context.py +50 -0
- dex/workflow_info.py +21 -0
- dex/workflow_options.py +79 -0
- dex/workflow_state.py +134 -0
- dex/workflow_state_options.py +160 -0
- dex_python_sdk-0.0.1.dist-info/METADATA +140 -0
- dex_python_sdk-0.0.1.dist-info/RECORD +93 -0
- dex_python_sdk-0.0.1.dist-info/WHEEL +4 -0
- dex_python_sdk-0.0.1.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import time
|
|
16
|
+
|
|
17
|
+
from dex.command_request import (
|
|
18
|
+
CommandRequest,
|
|
19
|
+
InternalChannelCommand,
|
|
20
|
+
SignalChannelCommand,
|
|
21
|
+
)
|
|
22
|
+
from dex.command_results import CommandResults
|
|
23
|
+
from dex.communication import Communication
|
|
24
|
+
from dex.communication_schema import CommunicationMethod, CommunicationSchema
|
|
25
|
+
from dex.persistence import Persistence
|
|
26
|
+
from dex.persistence_schema import PersistenceField, PersistenceSchema
|
|
27
|
+
from dex.rpc import rpc
|
|
28
|
+
from dex.state_decision import StateDecision
|
|
29
|
+
from dex.state_schema import StateSchema
|
|
30
|
+
from dex.workflow import ObjectWorkflow
|
|
31
|
+
from dex.workflow_context import WorkflowContext
|
|
32
|
+
from dex.workflow_state import T, WorkflowState
|
|
33
|
+
|
|
34
|
+
test_signal_channel = "test-1"
|
|
35
|
+
test_internal_channel = "test-2"
|
|
36
|
+
|
|
37
|
+
da_counter = "counter"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class WaitState(WorkflowState[bool]):
|
|
41
|
+
def wait_until(
|
|
42
|
+
self,
|
|
43
|
+
ctx: WorkflowContext,
|
|
44
|
+
use_signal: T,
|
|
45
|
+
persistence: Persistence,
|
|
46
|
+
communication: Communication,
|
|
47
|
+
) -> CommandRequest:
|
|
48
|
+
if use_signal:
|
|
49
|
+
return CommandRequest.for_all_command_completed(
|
|
50
|
+
SignalChannelCommand.by_name(test_signal_channel),
|
|
51
|
+
)
|
|
52
|
+
else:
|
|
53
|
+
return CommandRequest.for_all_command_completed(
|
|
54
|
+
InternalChannelCommand.by_name(test_internal_channel),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def execute(
|
|
58
|
+
self,
|
|
59
|
+
ctx: WorkflowContext,
|
|
60
|
+
use_signal: T,
|
|
61
|
+
command_results: CommandResults,
|
|
62
|
+
persistence: Persistence,
|
|
63
|
+
communication: Communication,
|
|
64
|
+
) -> StateDecision:
|
|
65
|
+
counter = persistence.get_data_attribute(da_counter)
|
|
66
|
+
if counter is None:
|
|
67
|
+
counter = 0
|
|
68
|
+
counter += 1
|
|
69
|
+
persistence.set_data_attribute(da_counter, counter)
|
|
70
|
+
|
|
71
|
+
if ctx.state_execution_id == "WaitState-1":
|
|
72
|
+
# wait for 3 seconds so that the channel can have a new message
|
|
73
|
+
time.sleep(3)
|
|
74
|
+
if use_signal:
|
|
75
|
+
return StateDecision.force_complete_if_signal_channel_empty_or_else(
|
|
76
|
+
test_signal_channel, counter, WaitState, use_signal
|
|
77
|
+
)
|
|
78
|
+
else:
|
|
79
|
+
return StateDecision.force_complete_if_internal_channel_empty_or_else(
|
|
80
|
+
test_internal_channel, counter, WaitState, use_signal
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ConditionalCompleteWorkflow(ObjectWorkflow):
|
|
85
|
+
def get_communication_schema(self) -> CommunicationSchema:
|
|
86
|
+
return CommunicationSchema.create(
|
|
87
|
+
CommunicationMethod.signal_channel_def(test_signal_channel, int),
|
|
88
|
+
CommunicationMethod.internal_channel_def(test_internal_channel, int),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def get_persistence_schema(self) -> PersistenceSchema:
|
|
92
|
+
return PersistenceSchema.create(
|
|
93
|
+
PersistenceField.data_attribute_def(da_counter, int),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def get_workflow_states(self) -> StateSchema:
|
|
97
|
+
return StateSchema.with_starting_state(WaitState())
|
|
98
|
+
|
|
99
|
+
@rpc()
|
|
100
|
+
def test_rpc_publish_channel(self, com: Communication):
|
|
101
|
+
com.publish_to_internal_channel(test_internal_channel, 0)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from dex.command_request import CommandRequest, TimerCommand
|
|
16
|
+
from dex.command_results import CommandResults
|
|
17
|
+
from dex.communication import Communication
|
|
18
|
+
from dex.persistence import Persistence
|
|
19
|
+
from dex.state_decision import StateDecision
|
|
20
|
+
from dex.state_schema import StateSchema
|
|
21
|
+
from dex.workflow import ObjectWorkflow
|
|
22
|
+
from dex.workflow_context import WorkflowContext
|
|
23
|
+
from dex.workflow_state import T, WorkflowState
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class WaitState(WorkflowState[None]):
|
|
27
|
+
def wait_until(
|
|
28
|
+
self,
|
|
29
|
+
ctx: WorkflowContext,
|
|
30
|
+
input: T,
|
|
31
|
+
persistence: Persistence,
|
|
32
|
+
communication: Communication,
|
|
33
|
+
) -> CommandRequest:
|
|
34
|
+
return CommandRequest.for_all_command_completed(
|
|
35
|
+
TimerCommand.by_seconds(10),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def execute(
|
|
39
|
+
self,
|
|
40
|
+
ctx: WorkflowContext,
|
|
41
|
+
input: T,
|
|
42
|
+
command_results: CommandResults,
|
|
43
|
+
persistence: Persistence,
|
|
44
|
+
communication: Communication,
|
|
45
|
+
) -> StateDecision:
|
|
46
|
+
|
|
47
|
+
return StateDecision.graceful_complete_workflow()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class DescribeWorkflow(ObjectWorkflow):
|
|
51
|
+
def get_workflow_states(self) -> StateSchema:
|
|
52
|
+
return StateSchema.with_starting_state(WaitState())
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from dex.command_results import CommandResults
|
|
16
|
+
from dex.communication import Communication
|
|
17
|
+
from dex.persistence import Persistence
|
|
18
|
+
from dex.persistence_schema import PersistenceField, PersistenceSchema
|
|
19
|
+
from dex.state_decision import StateDecision
|
|
20
|
+
from dex.state_schema import StateSchema
|
|
21
|
+
from dex.workflow import ObjectWorkflow
|
|
22
|
+
from dex.workflow_context import WorkflowContext
|
|
23
|
+
from dex.workflow_state import WorkflowState
|
|
24
|
+
|
|
25
|
+
TEST_DA_KEY = "test-da"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class State1(WorkflowState[None]):
|
|
29
|
+
def execute(
|
|
30
|
+
self,
|
|
31
|
+
ctx: WorkflowContext,
|
|
32
|
+
input: None,
|
|
33
|
+
command_results: CommandResults,
|
|
34
|
+
persistence: Persistence,
|
|
35
|
+
communication: Communication,
|
|
36
|
+
) -> StateDecision:
|
|
37
|
+
assert input is None
|
|
38
|
+
test_da = persistence.get_data_attribute(TEST_DA_KEY)
|
|
39
|
+
assert test_da is None
|
|
40
|
+
|
|
41
|
+
return StateDecision.graceful_complete_workflow(output="success")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class EmptyDataWorkflow(ObjectWorkflow):
|
|
45
|
+
def get_workflow_states(self) -> StateSchema:
|
|
46
|
+
return StateSchema.with_starting_state(State1())
|
|
47
|
+
|
|
48
|
+
def get_persistence_schema(self) -> PersistenceSchema:
|
|
49
|
+
return PersistenceSchema.create(
|
|
50
|
+
PersistenceField.data_attribute_def(TEST_DA_KEY, None),
|
|
51
|
+
)
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from dex.command_request import CommandRequest, InternalChannelCommand
|
|
16
|
+
from dex.command_results import CommandResults, InternalChannelCommandResult
|
|
17
|
+
from dex.communication import Communication
|
|
18
|
+
from dex.communication_schema import CommunicationMethod, CommunicationSchema
|
|
19
|
+
from dex.dex_api.models import ChannelRequestStatus
|
|
20
|
+
from dex.persistence import Persistence
|
|
21
|
+
from dex.state_decision import StateDecision
|
|
22
|
+
from dex.state_schema import StateSchema
|
|
23
|
+
from dex.workflow import ObjectWorkflow
|
|
24
|
+
from dex.workflow_context import WorkflowContext
|
|
25
|
+
from dex.workflow_state import T, WorkflowState
|
|
26
|
+
|
|
27
|
+
test_channel_name1 = "test-internal-channel-1"
|
|
28
|
+
test_channel_name2 = "test-internal-channel-2"
|
|
29
|
+
|
|
30
|
+
test_channel_name3 = "test-internal-channel-3"
|
|
31
|
+
test_channel_name4 = "test-internal-channel-4"
|
|
32
|
+
|
|
33
|
+
test_channel_name_prefix = "test-internal-channel-prefix-"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class InitState(WorkflowState[None]):
|
|
37
|
+
def execute(
|
|
38
|
+
self,
|
|
39
|
+
ctx: WorkflowContext,
|
|
40
|
+
input: T,
|
|
41
|
+
command_results: CommandResults,
|
|
42
|
+
persistence: Persistence,
|
|
43
|
+
communication: Communication,
|
|
44
|
+
) -> StateDecision:
|
|
45
|
+
return StateDecision.multi_next_states(
|
|
46
|
+
WaitAnyWithPublishState, WaitAllThenPublishState
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class WaitAnyWithPublishState(WorkflowState[None]):
|
|
51
|
+
def wait_until(
|
|
52
|
+
self,
|
|
53
|
+
ctx: WorkflowContext,
|
|
54
|
+
input: T,
|
|
55
|
+
persistence: Persistence,
|
|
56
|
+
communication: Communication,
|
|
57
|
+
) -> CommandRequest:
|
|
58
|
+
communication.publish_to_internal_channel(test_channel_name3, 123)
|
|
59
|
+
communication.publish_to_internal_channel(test_channel_name4, "str-value")
|
|
60
|
+
communication.publish_to_internal_channel(
|
|
61
|
+
test_channel_name_prefix + "abc", "str-value-for-prefix"
|
|
62
|
+
)
|
|
63
|
+
return CommandRequest.for_any_command_completed(
|
|
64
|
+
InternalChannelCommand.by_name(test_channel_name1),
|
|
65
|
+
InternalChannelCommand.by_name(test_channel_name2),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def execute(
|
|
69
|
+
self,
|
|
70
|
+
ctx: WorkflowContext,
|
|
71
|
+
input: T,
|
|
72
|
+
command_results: CommandResults,
|
|
73
|
+
persistence: Persistence,
|
|
74
|
+
communication: Communication,
|
|
75
|
+
) -> StateDecision:
|
|
76
|
+
assert len(command_results.internal_channel_commands) == 2
|
|
77
|
+
assert command_results.internal_channel_commands[
|
|
78
|
+
0
|
|
79
|
+
] == InternalChannelCommandResult(
|
|
80
|
+
channel_name=test_channel_name1,
|
|
81
|
+
command_id="",
|
|
82
|
+
status=ChannelRequestStatus.WAITING,
|
|
83
|
+
value=None,
|
|
84
|
+
)
|
|
85
|
+
assert command_results.internal_channel_commands[
|
|
86
|
+
1
|
|
87
|
+
] == InternalChannelCommandResult(
|
|
88
|
+
channel_name=test_channel_name2,
|
|
89
|
+
command_id="",
|
|
90
|
+
status=ChannelRequestStatus.RECEIVED,
|
|
91
|
+
value=None,
|
|
92
|
+
)
|
|
93
|
+
return StateDecision.graceful_complete_workflow()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class WaitAllThenPublishState(WorkflowState[None]):
|
|
97
|
+
def wait_until(
|
|
98
|
+
self,
|
|
99
|
+
ctx: WorkflowContext,
|
|
100
|
+
input: T,
|
|
101
|
+
persistence: Persistence,
|
|
102
|
+
communication: Communication,
|
|
103
|
+
) -> CommandRequest:
|
|
104
|
+
return CommandRequest.for_all_command_completed(
|
|
105
|
+
InternalChannelCommand.by_name(test_channel_name3),
|
|
106
|
+
InternalChannelCommand.by_name(test_channel_name4),
|
|
107
|
+
InternalChannelCommand.by_name(test_channel_name_prefix + "abc"),
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def execute(
|
|
111
|
+
self,
|
|
112
|
+
ctx: WorkflowContext,
|
|
113
|
+
input: T,
|
|
114
|
+
command_results: CommandResults,
|
|
115
|
+
persistence: Persistence,
|
|
116
|
+
communication: Communication,
|
|
117
|
+
) -> StateDecision:
|
|
118
|
+
communication.publish_to_internal_channel(test_channel_name2, None)
|
|
119
|
+
return StateDecision.dead_end
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class InternalChannelWorkflow(ObjectWorkflow):
|
|
123
|
+
def get_workflow_states(self) -> StateSchema:
|
|
124
|
+
return StateSchema.with_starting_state(
|
|
125
|
+
InitState(), WaitAnyWithPublishState(), WaitAllThenPublishState()
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
def get_communication_schema(self) -> CommunicationSchema:
|
|
129
|
+
return CommunicationSchema.create(
|
|
130
|
+
CommunicationMethod.internal_channel_def(test_channel_name1, int),
|
|
131
|
+
CommunicationMethod.internal_channel_def(test_channel_name2, None),
|
|
132
|
+
CommunicationMethod.internal_channel_def(test_channel_name3, int),
|
|
133
|
+
CommunicationMethod.internal_channel_def(test_channel_name4, str),
|
|
134
|
+
CommunicationMethod.internal_channel_def_by_prefix(
|
|
135
|
+
test_channel_name_prefix, str
|
|
136
|
+
),
|
|
137
|
+
)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from dex.command_request import CommandRequest, InternalChannelCommand
|
|
16
|
+
from dex.command_results import CommandResults
|
|
17
|
+
from dex.communication import Communication
|
|
18
|
+
from dex.communication_schema import CommunicationMethod, CommunicationSchema
|
|
19
|
+
from dex.persistence import Persistence
|
|
20
|
+
from dex.state_decision import StateDecision
|
|
21
|
+
from dex.state_schema import StateSchema
|
|
22
|
+
from dex.workflow import ObjectWorkflow
|
|
23
|
+
from dex.workflow_context import WorkflowContext
|
|
24
|
+
from dex.workflow_state import T, WorkflowState
|
|
25
|
+
|
|
26
|
+
internal_channel_name = "internal-channel-1"
|
|
27
|
+
|
|
28
|
+
test_non_prefix_channel_name = "test-channel-"
|
|
29
|
+
test_non_prefix_channel_name_with_suffix = test_non_prefix_channel_name + "abc"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class InitState(WorkflowState[None]):
|
|
33
|
+
def execute(
|
|
34
|
+
self,
|
|
35
|
+
ctx: WorkflowContext,
|
|
36
|
+
input: T,
|
|
37
|
+
command_results: CommandResults,
|
|
38
|
+
persistence: Persistence,
|
|
39
|
+
communication: Communication,
|
|
40
|
+
) -> StateDecision:
|
|
41
|
+
return StateDecision.multi_next_states(
|
|
42
|
+
WaitAnyWithPublishState, WaitAllThenPublishState
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class WaitAnyWithPublishState(WorkflowState[None]):
|
|
47
|
+
def wait_until(
|
|
48
|
+
self,
|
|
49
|
+
ctx: WorkflowContext,
|
|
50
|
+
input: T,
|
|
51
|
+
persistence: Persistence,
|
|
52
|
+
communication: Communication,
|
|
53
|
+
) -> CommandRequest:
|
|
54
|
+
# Trying to publish to a non-existing channel; this would only work if test_channel_name_non_prefix was defined as a prefix channel
|
|
55
|
+
communication.publish_to_internal_channel(
|
|
56
|
+
test_non_prefix_channel_name_with_suffix, "str-value-for-prefix"
|
|
57
|
+
)
|
|
58
|
+
return CommandRequest.for_any_command_completed(
|
|
59
|
+
InternalChannelCommand.by_name(internal_channel_name),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def execute(
|
|
63
|
+
self,
|
|
64
|
+
ctx: WorkflowContext,
|
|
65
|
+
input: T,
|
|
66
|
+
command_results: CommandResults,
|
|
67
|
+
persistence: Persistence,
|
|
68
|
+
communication: Communication,
|
|
69
|
+
) -> StateDecision:
|
|
70
|
+
return StateDecision.graceful_complete_workflow()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class WaitAllThenPublishState(WorkflowState[None]):
|
|
74
|
+
def wait_until(
|
|
75
|
+
self,
|
|
76
|
+
ctx: WorkflowContext,
|
|
77
|
+
input: T,
|
|
78
|
+
persistence: Persistence,
|
|
79
|
+
communication: Communication,
|
|
80
|
+
) -> CommandRequest:
|
|
81
|
+
return CommandRequest.for_all_command_completed(
|
|
82
|
+
InternalChannelCommand.by_name(test_non_prefix_channel_name),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def execute(
|
|
86
|
+
self,
|
|
87
|
+
ctx: WorkflowContext,
|
|
88
|
+
input: T,
|
|
89
|
+
command_results: CommandResults,
|
|
90
|
+
persistence: Persistence,
|
|
91
|
+
communication: Communication,
|
|
92
|
+
) -> StateDecision:
|
|
93
|
+
communication.publish_to_internal_channel(internal_channel_name, None)
|
|
94
|
+
return StateDecision.dead_end
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class InternalChannelWorkflowWithNoPrefixChannel(ObjectWorkflow):
|
|
98
|
+
def get_workflow_states(self) -> StateSchema:
|
|
99
|
+
return StateSchema.with_starting_state(
|
|
100
|
+
InitState(), WaitAnyWithPublishState(), WaitAllThenPublishState()
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def get_communication_schema(self) -> CommunicationSchema:
|
|
104
|
+
return CommunicationSchema.create(
|
|
105
|
+
CommunicationMethod.internal_channel_def(internal_channel_name, None),
|
|
106
|
+
# Defining a standard channel (non-prefix) to make sure messages to the channel with a suffix added will not be accepted
|
|
107
|
+
CommunicationMethod.internal_channel_def(test_non_prefix_channel_name, str),
|
|
108
|
+
)
|