@@ -12,6 +12,7 @@ use temporal_client::SharedNamespaceWorkerTrait;
1212use temporal_sdk_core_api:: worker:: { WorkerConfigBuilder , WorkerVersioningStrategy } ;
1313use temporal_sdk_core_protos:: temporal:: api:: worker:: v1:: WorkerHeartbeat ;
1414use tokio:: sync:: Notify ;
15+ use tokio_util:: sync:: CancellationToken ;
1516
1617/// Callback used to collect heartbeat data from each worker at the time of heartbeat
1718pub ( crate ) type HeartbeatFn = Box < dyn Fn ( ) -> WorkerHeartbeat + Send + Sync > ;
@@ -22,6 +23,7 @@ pub(crate) type HeartbeatFn = Box<dyn Fn() -> WorkerHeartbeat + Send + Sync>;
2223pub ( crate ) struct SharedNamespaceWorker {
2324 heartbeat_map : Arc < Mutex < HashMap < String , HeartbeatFn > > > ,
2425 namespace : String ,
26+ cancel : CancellationToken ,
2527}
2628
2729impl SharedNamespaceWorker {
@@ -51,12 +53,16 @@ impl SharedNamespaceWorker {
5153 TaskPollers :: Real ,
5254 telemetry,
5355 None ,
56+ true ,
5457 ) ;
5558
5659 let last_heartbeat_time_map = Mutex :: new ( HashMap :: new ( ) ) ;
5760
5861 // heartbeat task
5962 let reset_notify = Arc :: new ( Notify :: new ( ) ) ;
63+ let cancel = CancellationToken :: new ( ) ;
64+ let child = cancel. child_token ( ) ;
65+
6066 let client_clone = client;
6167 let namespace_clone = namespace. clone ( ) ;
6268
@@ -67,15 +73,6 @@ impl SharedNamespaceWorker {
6773 let mut ticker = tokio:: time:: interval ( heartbeat_interval) ;
6874 ticker. tick ( ) . await ;
6975 loop {
70- // TODO: Race condition here, can technically shut down before anything is ever initialized
71- if heartbeat_map_clone. lock ( ) . is_empty ( ) {
72- println ! (
73- "// TODO: Race condition here, can technically shut down before anything is ever initialized"
74- ) ;
75- worker. shutdown ( ) . await ;
76- return ;
77- }
78-
7976 tokio:: select! {
8077 _ = ticker. tick( ) => {
8178 let mut hb_to_send = Vec :: new( ) ;
@@ -94,10 +91,18 @@ impl SharedNamespaceWorker {
9491 } else {
9592 None
9693 } ;
94+ let sdk_name_and_ver = client_clone. sdk_name_and_version( ) ;
9795
9896 heartbeat. elapsed_since_last_heartbeat = elapsed_since_last_heartbeat;
9997 heartbeat. heartbeat_time = Some ( now. into( ) ) ;
10098
99+ // All of these heartbeat details rely on a client. Due to type limitations
100+ // from the dependency graph of worker_registry, this must be populated
101+ // from within SharedNamespaceWorker to get the current and proper client
102+ heartbeat. worker_identity = client_clone. identity( ) ;
103+ heartbeat. sdk_name = sdk_name_and_ver. 0 ;
104+ heartbeat. sdk_version = sdk_name_and_ver. 1 ;
105+
101106 hb_to_send. push( heartbeat) ;
102107
103108 last_heartbeat_time_map. insert( instance_key. clone( ) , now) ;
@@ -115,13 +120,18 @@ impl SharedNamespaceWorker {
115120 _ = reset_notify. notified( ) => {
116121 ticker. reset( ) ;
117122 }
123+ _ = child. cancelled( ) => {
124+ worker. shutdown( ) . await ;
125+ return ;
126+ }
118127 }
119128 }
120129 } ) ;
121130
122131 Self {
123132 heartbeat_map,
124133 namespace,
134+ cancel,
125135 }
126136 }
127137}
@@ -136,10 +146,11 @@ impl SharedNamespaceWorkerTrait for SharedNamespaceWorker {
136146 worker_instance_key : String ,
137147 ) -> ( Option < Box < dyn Fn ( ) -> WorkerHeartbeat + Send + Sync > > , bool ) {
138148 let mut heartbeat_map = self . heartbeat_map . lock ( ) ;
139- (
140- heartbeat_map. remove ( & worker_instance_key) ,
141- heartbeat_map. is_empty ( ) ,
142- )
149+ let heartbeat_callback = heartbeat_map. remove ( & worker_instance_key) ;
150+ if heartbeat_map. is_empty ( ) {
151+ self . cancel . cancel ( ) ;
152+ }
153+ ( heartbeat_callback, heartbeat_map. is_empty ( ) )
143154 }
144155 fn register_callback (
145156 & self ,
@@ -230,6 +241,7 @@ mod tests {
230241 client. clone ( ) ,
231242 None ,
232243 Some ( Duration :: from_millis ( 100 ) ) ,
244+ false ,
233245 ) ;
234246
235247 tokio:: time:: sleep ( Duration :: from_millis ( 250 ) ) . await ;
0 commit comments