1414from enum import Enum
1515from typing import Any , Generator , List , Optional , Sequence , TypeVar , Union
1616import uuid
17+ from durabletask .entities .entity_lock import EntityLock
1718from packaging .version import InvalidVersion , parse
1819
1920import grpc
2324from durabletask .internal .entity_state_shim import StateShim
2425from durabletask .internal .helpers import new_timestamp
2526from durabletask .entities .entity_instance_id import EntityInstanceId
26- from durabletask .internal .entity_lock_releaser import EntityLockReleaser
2727from durabletask .internal .orchestration_entity_context import OrchestrationEntityContext
2828import durabletask .internal .helpers as ph
2929import durabletask .internal .exceptions as pe
@@ -994,7 +994,7 @@ def signal_entity(
994994 id , entity_id , operation , input
995995 )
996996
997- def lock_entities (self , entities : list [EntityInstanceId ]) -> EntityLockReleaser :
997+ def lock_entities (self , entities : list [EntityInstanceId ]) -> EntityLock :
998998 id = self .next_sequence_number ()
999999
10001000 self .lock_entities_function_helper (
@@ -1003,7 +1003,7 @@ def lock_entities(self, entities: list[EntityInstanceId]) -> EntityLockReleaser:
10031003
10041004 # Todo: EntityLockReleaser should be a disposable that uses python's using statement
10051005 # and should release the locks when disposed
1006- return EntityLockReleaser ( entities )
1006+ return EntityLock ( self . _entity_context , entities )
10071007
10081008 def call_sub_orchestrator (
10091009 self ,
@@ -1129,26 +1129,22 @@ def lock_entities_function_helper(
11291129 id : Optional [int ],
11301130 entity_ids : List [EntityInstanceId ]
11311131 ):
1132+ valid , message = self ._entity_context .validate_acquire_transition ()
1133+ if not valid :
1134+ raise RuntimeError (message )
1135+
11321136 if id is None :
11331137 id = self .next_sequence_number ()
11341138
1135- transition_valid , error_message = self ._entity_context .validate_acquire_transition ()
1136- if not transition_valid :
1137- raise RuntimeError (error_message )
1139+ # Use a deterministically replayable unique ID for this lock request
1140+ critical_section_id = f"{ self .instance_id } :{ id } "
11381141
1139- # Acquire the locks in a globally fixed order to avoid deadlocks
1140- # Also remove duplicates - this can be optimized for perf if necessary
1141- entity_ids = sorted (entity_ids )
1142- entity_ids_dedup = []
1143- for i , entity_id in enumerate (entity_ids ):
1144- if entity_id != entity_ids [i - 1 ] if i > 0 else None :
1145- entity_ids_dedup .append (entity_id )
1142+ event_name , request , target = self ._entity_context .emit_acquire_message (critical_section_id , entity_ids )
11461143
1147- # Use a deterministically replayable unique ID for this lock request
1148- # TODO: Implement deterministically replayable IDs
1149- critical_section_id = str (uuid .uuid4 ())
1144+ if not event_name or not request or not target :
1145+ raise RuntimeError ("Failed to create entity lock request." )
11501146
1151- action = ph .new_lock_entities_action (id , self . instance_id , critical_section_id , entity_ids_dedup )
1147+ action = ph .new_lock_entities_action (id , request )
11521148 self ._pending_actions [id ] = action
11531149
11541150 def wait_for_external_event (self , name : str ) -> task .Task :
0 commit comments