|
| 1 | + |
| 2 | +from typing import Any, Optional, Type, TypeVar, Union, overload |
| 3 | +import uuid |
| 4 | +from durabletask.entities.entity_instance_id import EntityInstanceId |
| 5 | +from durabletask.internal import helpers, shared |
| 6 | +from durabletask.internal.entity_state_shim import StateShim |
| 7 | +import durabletask.internal.orchestrator_service_pb2 as pb |
| 8 | + |
| 9 | +TState = TypeVar("TState") |
| 10 | + |
| 11 | + |
| 12 | +class EntityContext: |
| 13 | + def __init__(self, orchestration_id: str, operation: str, state: StateShim, entity_id: EntityInstanceId): |
| 14 | + self._orchestration_id = orchestration_id |
| 15 | + self._operation = operation |
| 16 | + self._state = state |
| 17 | + self._entity_id = entity_id |
| 18 | + |
| 19 | + @property |
| 20 | + def orchestration_id(self) -> str: |
| 21 | + """Get the ID of the orchestration instance that scheduled this entity. |
| 22 | +
|
| 23 | + Returns |
| 24 | + ------- |
| 25 | + str |
| 26 | + The ID of the current orchestration instance. |
| 27 | + """ |
| 28 | + return self._orchestration_id |
| 29 | + |
| 30 | + @property |
| 31 | + def operation(self) -> str: |
| 32 | + """Get the operation associated with this entity invocation. |
| 33 | +
|
| 34 | + The operation is a string that identifies the specific action being |
| 35 | + performed on the entity. It can be used to distinguish between |
| 36 | + multiple operations that are part of the same entity invocation. |
| 37 | +
|
| 38 | + Returns |
| 39 | + ------- |
| 40 | + str |
| 41 | + The operation associated with this entity invocation. |
| 42 | + """ |
| 43 | + return self._operation |
| 44 | + |
| 45 | + @overload |
| 46 | + def get_state(self, intended_type: Type[TState], default: TState) -> TState: |
| 47 | + ... |
| 48 | + |
| 49 | + @overload |
| 50 | + def get_state(self, intended_type: Type[TState]) -> Optional[TState]: |
| 51 | + ... |
| 52 | + |
| 53 | + @overload |
| 54 | + def get_state(self, intended_type: None = None, default: Any = None) -> Any: |
| 55 | + ... |
| 56 | + |
| 57 | + def get_state(self, intended_type: Optional[Type[TState]] = None, default: Optional[TState] = None) -> Union[None, TState, Any]: |
| 58 | + """Get the current state of the entity, optionally converting it to a specified type. |
| 59 | +
|
| 60 | + Parameters |
| 61 | + ---------- |
| 62 | + intended_type : Type[TState] | None, optional |
| 63 | + The type to which the state should be converted. If None, the state is returned as-is. |
| 64 | + default : TState, optional |
| 65 | + The default value to return if the state is not found or cannot be converted. |
| 66 | +
|
| 67 | + Returns |
| 68 | + ------- |
| 69 | + TState | Any |
| 70 | + The current state of the entity, optionally converted to the specified type. |
| 71 | + """ |
| 72 | + return self._state.get_state(intended_type, default) |
| 73 | + |
| 74 | + def set_state(self, new_state: Any): |
| 75 | + """Set the state of the entity to a new value. |
| 76 | +
|
| 77 | + Parameters |
| 78 | + ---------- |
| 79 | + new_state : Any |
| 80 | + The new state to set for the entity. |
| 81 | + """ |
| 82 | + self._state.set_state(new_state) |
| 83 | + |
| 84 | + def signal_entity(self, entity_instance_id: EntityInstanceId, operation: str, input: Optional[Any] = None) -> None: |
| 85 | + """Signal another entity to perform an operation. |
| 86 | +
|
| 87 | + Parameters |
| 88 | + ---------- |
| 89 | + entity_instance_id : EntityInstanceId |
| 90 | + The ID of the entity instance to signal. |
| 91 | + operation : str |
| 92 | + The operation to perform on the entity. |
| 93 | + input : Any, optional |
| 94 | + The input to provide to the entity for the operation. |
| 95 | + """ |
| 96 | + encoded_input = shared.to_json(input) if input is not None else None |
| 97 | + self._state.add_operation_action( |
| 98 | + pb.OperationAction( |
| 99 | + sendSignal=pb.SendSignalAction( |
| 100 | + instanceId=str(entity_instance_id), |
| 101 | + name=operation, |
| 102 | + input=helpers.get_string_value(encoded_input), |
| 103 | + scheduledTime=None, |
| 104 | + requestTime=None, |
| 105 | + parentTraceContext=None, |
| 106 | + ) |
| 107 | + ) |
| 108 | + ) |
| 109 | + |
| 110 | + def schedule_new_orchestration(self, orchestration_name: str, input: Optional[Any] = None, instance_id: Optional[str] = None) -> str: |
| 111 | + """Schedule a new orchestration instance. |
| 112 | +
|
| 113 | + Parameters |
| 114 | + ---------- |
| 115 | + orchestration_name : str |
| 116 | + The name of the orchestration to schedule. |
| 117 | + input : Any, optional |
| 118 | + The input to provide to the new orchestration. |
| 119 | + instance_id : str, optional |
| 120 | + The instance ID to assign to the new orchestration. If None, a new ID will be generated. |
| 121 | +
|
| 122 | + Returns |
| 123 | + ------- |
| 124 | + str |
| 125 | + The instance ID of the scheduled orchestration. |
| 126 | + """ |
| 127 | + encoded_input = shared.to_json(input) if input is not None else None |
| 128 | + if not instance_id: |
| 129 | + instance_id = uuid.uuid4().hex |
| 130 | + self._state.add_operation_action( |
| 131 | + pb.OperationAction( |
| 132 | + startNewOrchestration=pb.StartNewOrchestrationAction( |
| 133 | + instanceId=instance_id, |
| 134 | + name=orchestration_name, |
| 135 | + input=helpers.get_string_value(encoded_input), |
| 136 | + version=None, |
| 137 | + scheduledTime=None, |
| 138 | + requestTime=None, |
| 139 | + parentTraceContext=None |
| 140 | + ) |
| 141 | + ) |
| 142 | + ) |
| 143 | + return instance_id |
| 144 | + |
| 145 | + @property |
| 146 | + def entity_id(self) -> EntityInstanceId: |
| 147 | + """Get the ID of the entity instance. |
| 148 | +
|
| 149 | + Returns |
| 150 | + ------- |
| 151 | + str |
| 152 | + The ID of the current entity instance. |
| 153 | + """ |
| 154 | + return self._entity_id |
0 commit comments