10000 Step Functions: Support for Aliasing (#12326) · localstack/localstack@596fae6 · GitHub
[go: up one dir, main page]

Skip to content

Commit 596fae6

Browse files
authored
Step Functions: Support for Aliasing (#12326)
1 parent 3fa9a9e commit 596fae6

File tree

10 files changed

+2203
-15
lines changed

10 files changed

+2203
-15
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
from __future__ import annotations
2+
3+
import copy
4+
import datetime
5+
import random
6+
import threading
7+
from typing import Final, Optional
8+
9+
from localstack.aws.api.stepfunctions import (
10+
AliasDescription,
11+
Arn,
12+
CharacterRestrictedName,
13+
DescribeStateMachineAliasOutput,
14+
RoutingConfigurationList,
15+
StateMachineAliasListItem,
16+
)
17+
18+
19+
class Alias:
20+
_mutex: Final[threading.Lock]
21+
update_date: Optional[datetime.datetime]
22+
name: Final[CharacterRestrictedName]
23+
_description: Optional[AliasDescription]
24+
_routing_configuration_list: RoutingConfigurationList
25+
_state_machine_version_arns: list[Arn]
26+
_execution_probability_distribution: list[int]
27+
state_machine_alias_arn: Final[Arn]
28+
create_date: datetime.datetime
29+
30+
def __init__(
31+
self,
32+
state_machine_arn: Arn,
33+
name: CharacterRestrictedName,
34+
description: Optional[AliasDescription],
35+
routing_configuration_list: RoutingConfigurationList,
36+
):
37+
self._mutex = threading.Lock()
38+
self.update_date = None
39+
self.name = name
40+
self._description = None
41+
self.state_machine_alias_arn = f"{state_machine_arn}:{name}"
42+
self.update(description=description, routing_configuration_list=routing_configuration_list)
43+
self.create_date = self._get_mutex_date()
44+
45+
def __hash__(self):
46+
return hash(self.state_machine_alias_arn)
47+
48+
def __eq__(self, other):
49+
if isinstance(other, Alias):
50+
return self.is_idempotent(other=other)
51+
return False
52+
53+
def is_idempotent(self, other: Alias) -> bool:
54+
return all(
55+
[
56+
self.state_machine_alias_arn == other.state_machine_alias_arn,
57+
self.name == other.name,
58+
self._description == other._description,
59+
self._routing_configuration_list == other._routing_configuration_list,
60+
]
61+
)
62+
63+
@staticmethod
64+
def _get_mutex_date() -> datetime.datetime:
65+
return datetime.datetime.now(tz=datetime.timezone.utc)
66+
67+
def get_routing_configuration_list(self) -> RoutingConfigurationList:
68+
return copy.deepcopy(self._routing_configuration_list)
69+
70+
def is_router_for(self, state_machine_version_arn: Arn) -> bool:
71+
with self._mutex:
72+
return state_machine_version_arn in self._state_machine_version_arns
73+
74+
def update(
75+
self,
76+
description: Optional[AliasDescription],
77+
routing_configuration_list: RoutingConfigurationList,
78+
) -> None:
79+
with self._mutex:
80+
self.update_date = self._get_mutex_date()
81+
82+
if description is not None:
83+
self._description = description
84+
85+
if routing_configuration_list:
86+
self._routing_configuration_list = routing_configuration_list
87+
self._state_machine_version_arns = list()
88+
self._execution_probability_distribution = list()
89+
for routing_configuration in routing_configuration_list:
90+
self._state_machine_version_arns.append(
91+
routing_configuration["stateMachineVersionArn"]
92+
)
93+
self._execution_probability_distribution.append(routing_configuration["weight"])
94+
95+
def sample(self):
96+
with self._mutex:
97+
samples = random.choices(
98+
self._state_machine_version_arns,
99+
weights=self._execution_probability_distribution,
100+
k=1,
101+
)
102+
state_machine_version_arn = samples[0]
103+
return state_machine_version_arn
104+
105+
def to_description(self) -> DescribeStateMachineAliasOutput:
106+
with self._mutex:
107+
description = DescribeStateMachineAliasOutput(
108+
creationDate=self.create_date,
109+
name=self.name,
110+
description=self._description,
111+
routingConfiguration=self._routing_configuration_list,
112+
stateMachineAliasArn=self.state_machine_alias_arn,
113+
)
114+
if self.update_date is not None:
115+
description["updateDate"] = self.update_date
116+
return description
117+
118+
def to_item(self) -> StateMachineAliasListItem:
119+
return StateMachineAliasListItem(
120+
stateMachineAliasArn=self.state_machine_alias_arn, creationDate=self.create_date
121+
)

localstack-core/localstack/services/stepfunctions/backend/execution.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ class Execution:
103103
region_name: str
104104

105105
state_machine: Final[StateMachineInstance]
106+
state_machine_arn: Final[Arn]
107+
state_machine_version_arn: Final[Optional[Arn]]
108+
state_machine_alias_arn: Final[Optional[Arn]]
109+
106110
start_date: Final[Timestamp]
107111
input_data: Final[Optional[json]]
108112
input_details: Final[Optional[CloudWatchEventsExecutionDataDetails]]
@@ -136,6 +140,7 @@ def __init__(
136140
activity_store: dict[Arn, Activity],
137141
input_data: Optional[json] = None,
138142
trace_header: Optional[TraceHeader] = None,
143+
state_machine_alias_arn: Optional[Arn] = None,
139144
):
140145
self.name = name
141146
self.sm_type = sm_type
@@ -144,6 +149,13 @@ def __init__(
144149
self.account_id = account_id
145150
self.region_name = region_name
146151
self.state_machine = state_machine
152+
if isinstance(state_machine, StateMachineVersion):
153+
self.state_machine_arn = state_machine.source_arn
154+
self.state_machine_version_arn = state_machine.arn
155+
else:
156+
self.state_machine_arn = state_machine.arn
157+
self.state_machine_version_arn = None
158+
self.state_machine_alias_arn = state_machine_alias_arn
147159
self.start_date = start_date
148160
self._cloud_watch_logging_session = cloud_watch_logging_session
149161
self.input_data = input_data
@@ -167,7 +179,7 @@ def to_start_output(self) -> StartExecutionOutput:
167179
def to_describe_output(self) -> DescribeExecutionOutput:
168180
describe_output = DescribeExecutionOutput(
169181
executionArn=self.exec_arn,
170-
stateMachineArn=self.state_machine.arn,
182+
stateMachineArn=self.state_machine_arn,
171183
name=self.name,
172184
status=self.exec_status,
173185
startDate=self.start_date,
@@ -183,6 +195,10 @@ def to_describe_output(self) -> DescribeExecutionOutput:
183195
describe_output["error"] = self.error
184196
if self.cause is not None:
185197
describe_output["cause"] = self.cause
198+
if self.state_machine_version_arn is not None:
199+
describe_output["stateMachineVersionArn"] = self.state_machine_version_arn
200+
if self.state_machine_alias_arn is not None:
201+
describe_output["stateMachineAliasArn"] = self.state_machine_alias_arn
186202
return describe_output
187203

188204
def to_describe_state_machine_for_execution_output(
@@ -231,6 +247,8 @@ def to_execution_list_item(self) -> ExecutionListItem:
231247
)
232248
if state_machine_version_arn is not None:
233249
item["stateMachineVersionArn"] = state_machine_version_arn
250+
if self.state_machine_alias_arn is not None:
251+
item["stateMachineAliasArn"] = self.state_machine_alias_arn
234252
return item
235253

236254
def to_history_output(self) -> GetExecutionHistoryOutput:

localstack-core/localstack/services/stepfunctions/backend/state_machine.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from localstack.services.stepfunctions.asl.static_analyser.variable_references_static_analyser import (
3131
VariableReferencesStaticAnalyser,
3232
)
33+
from localstack.services.stepfunctions.backend.alias import Alias
3334
from localstack.utils.strings import long_uid
3435

3536

@@ -163,6 +164,7 @@ class StateMachineRevision(StateMachineInstance):
163164
_next_version_number: int
164165
versions: Final[dict[RevisionId, Arn]]
165166
tag_manager: Final[TagManager]
167+
aliases: Final[set[Alias]]
166168

167169
def __init__(
168170
self,
@@ -194,6 +196,7 @@ def __init__(
194196
self.tag_manager = TagManager()
195197
if tags:
196198
self.tag_manager.add_all(tags)
199+
self.aliases = set()
197200

198201
def create_revision(
199202
self,

localstack-core/localstack/services/stepfunctions/backend/store.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from localstack.aws.api.stepfunctions import Arn
55
from localstack.services.stepfunctions.backend.activity import Activity
6+
from localstack.services.stepfunctions.backend.alias import Alias
67
from localstack.services.stepfunctions.backend.execution import Execution
78
from localstack.services.stepfunctions.backend.state_machine import StateMachineInstance
89
from localstack.services.stores import AccountRegionBundle, BaseStore, LocalAttribute
@@ -11,6 +12,8 @@
1112
class SFNStore(BaseStore):
1213
# Maps ARNs to state machines.
1314
state_machines: Final[dict[Arn, StateMachineInstance]] = LocalAttribute(default=dict)
15+
# Map Alias ARNs to state machine aliases
16+
aliases: Final[dict[Arn, Alias]] = LocalAttribute(default=dict)
1417
# Maps Execution-ARNs to state machines.
1518
executions: Final[dict[Arn, Execution]] = LocalAttribute(
1619
default=OrderedDict

0 commit comments

Comments
 (0)
0