@@ -168,42 +168,67 @@ where
168
168
' service_handling: {
169
169
' drop_service: {
170
170
if let Some ( known_service) = services. get_mut ( target) {
171
- known_service. refcount = if known_service. refcount == 1 {
172
- known_service. runtimes . remove ( runtime_id) ;
173
- let mut status = known_service. status . lock ( ) . unwrap ( ) ;
174
- * status = match * status {
175
- KnownTargetStatus :: Pending => KnownTargetStatus :: Alive , // not really
176
- KnownTargetStatus :: Alive => KnownTargetStatus :: RemoveAt (
177
- Instant :: now ( ) + Duration :: from_secs ( 3666 ) ,
178
- ) ,
179
- KnownTargetStatus :: RemoveAt ( _) | KnownTargetStatus :: Removing ( _) => {
180
- unreachable ! ( )
171
+ known_service. refcount = match known_service. refcount {
172
+ 0 => {
173
+ // Handle the possible race condition where the service gets added AND
174
+ // removed while in Removing state.
175
+ let status = known_service. status . lock ( ) . unwrap ( ) ;
176
+ match * status {
177
+ KnownTargetStatus :: Removing ( ref future) => {
178
+ let future = future. clone ( ) ;
179
+ let runtime_id = runtime_id. to_string ( ) ;
180
+ let this = self . clone ( ) ;
181
+ let target = target. clone ( ) ;
182
+ tokio:: spawn ( async move {
183
+ future. await ;
184
+ this. remove_target ( runtime_id. as_str ( ) , & target) ;
185
+ } ) ;
186
+ return ;
187
+ }
188
+ _ => {
189
+ // It's already in process of being removed
190
+ return ;
191
+ }
181
192
}
182
- } ;
183
- // We've marked it Alive so that the Pending check in start_fetcher() will
184
- // fail
185
- if matches ! ( * status, KnownTargetStatus :: Alive ) {
186
- break ' drop_service;
187
193
}
188
- 0
189
- } else {
190
- if * known_service. fetcher . runtime_id . lock ( ) . unwrap ( ) == runtime_id {
191
- ' changed_rt_id: {
192
- for ( id, runtime) in self . runtimes . lock ( ) . unwrap ( ) . iter ( ) {
193
- if runtime. targets . len ( ) == 1
194
- && runtime. targets . contains_key ( target)
195
- {
196
- * known_service. fetcher . runtime_id . lock ( ) . unwrap ( ) =
197
- id. to_string ( ) ;
198
- break ' changed_rt_id;
194
+ 1 => {
195
+ known_service. runtimes . remove ( runtime_id) ;
196
+ let mut status = known_service. status . lock ( ) . unwrap ( ) ;
197
+ * status = match * status {
198
+ KnownTargetStatus :: Pending => KnownTargetStatus :: Alive , /* not really */
199
+ KnownTargetStatus :: Alive => KnownTargetStatus :: RemoveAt (
200
+ Instant :: now ( ) + Duration :: from_secs ( 3666 ) ,
201
+ ) ,
202
+ KnownTargetStatus :: RemoveAt ( _) | KnownTargetStatus :: Removing ( _) => {
203
+ unreachable ! ( )
204
+ }
205
+ } ;
206
+ // We've marked it Alive so that the Pending check in start_fetcher()
207
+ // will fail
208
+ if matches ! ( * status, KnownTargetStatus :: Alive ) {
209
+ break ' drop_service;
210
+ }
211
+ 0
212
+ }
213
+ _ => {
214
+ if * known_service. fetcher . runtime_id . lock ( ) . unwrap ( ) == runtime_id {
215
+ ' changed_rt_id: {
216
+ for ( id, runtime) in self . runtimes . lock ( ) . unwrap ( ) . iter ( ) {
217
+ if runtime. targets . len ( ) == 1
218
+ && runtime. targets . contains_key ( target)
219
+ {
220
+ * known_service. fetcher . runtime_id . lock ( ) . unwrap ( ) =
221
+ id. to_string ( ) ;
222
+ break ' changed_rt_id;
223
+ }
199
224
}
225
+ known_service. synthetic_id = true ;
226
+ * known_service. fetcher . runtime_id . lock ( ) . unwrap ( ) =
227
+ Self :: generate_synthetic_id ( ) ;
200
228
}
201
- known_service. synthetic_id = true ;
202
- * known_service. fetcher . runtime_id . lock ( ) . unwrap ( ) =
203
- Self :: generate_synthetic_id ( ) ;
204
229
}
230
+ known_service. refcount - 1
205
231
}
206
- known_service. refcount - 1
207
232
} ;
208
233
break ' service_handling;
209
234
}
0 commit comments