@@ -212,40 +212,49 @@ extension Analytics {
212
212
flushGroup. enter ( )
213
213
214
214
apply { plugin in
215
+ // we want to enter as soon as possible. waiting to do it from
216
+ // another queue just takes too long.
215
217
operatingMode. run ( queue: configuration. values. flushQueue) {
216
218
if let p = plugin as? FlushCompletion {
217
- // this is async
218
- // flush(group:completion:) handles the enter/leave.
219
+ // flush handles the groups enter/leave calls
219
220
p. flush ( group: flushGroup) { plugin in
220
221
// we don't really care about the plugin value .. yet.
221
222
}
222
223
} else if let p = plugin as? EventPlugin {
223
- // we have no idea if this will be async or not, assume it's sync.
224
224
flushGroup. enter ( )
225
+ // we have no idea if this will be async or not, assume it's sync.
225
226
p. flush ( )
226
227
flushGroup. leave ( )
227
228
}
228
229
}
229
230
}
230
231
231
- // if we're not in server mode, we need to be notified when it's done.
232
- if let completion, operatingMode != . synchronous {
233
- // set up our callback to know when the group has completed, if we're not
234
- // in .server operating mode.
235
- flushGroup. notify ( queue: configuration. values. flushQueue) {
236
- DispatchQueue . main. async { completion ( ) }
237
- }
238
- }
239
-
240
232
flushGroup. leave ( ) // matches our initial enter().
241
233
242
- // if we ARE in server mode, we need to wait on the group.
234
+ // if we ARE in sync mode, we need to wait on the group.
243
235
// This effectively ends up being a `sync` operation.
244
236
if operatingMode == . synchronous {
245
237
flushGroup. wait ( )
246
238
// we need to call completion on our own since
247
- // we skipped setting up notify.
248
- if let completion { DispatchQueue . main. async { completion ( ) } }
239
+ // we skipped setting up notify. we don't need to do it on
240
+ // .main since we are in synchronous mode.
241
+ if let completion { completion ( ) }
242
+ } else if operatingMode == . asynchronous {
243
+ // if we're not, flip over to our serial queue, tell it to wait on the flush
244
+ // group to complete if we have a completion to hit. Otherwise, no need to
245
+ // wait on completion.
246
+ if let completion {
247
+ // NOTE: DispatchGroup's `notify` method on linux ended up getting called
248
+ // before the tasks have actually completed, so we went with this instead.
249
+ OperatingMode . defaultQueue. async { [ weak self] in
250
+ let timedOut = flushGroup. wait ( timeout: . now( ) + 15 /*seconds*/)
251
+ if timedOut == . timedOut {
252
+ self ? . log ( message: " flush(completion:) timed out waiting for completion. " )
253
+ }
254
+ completion ( )
255
+ //DispatchQueue.main.async { completion() }
256
+ }
257
+ }
249
258
}
250
259
}
251
260
@@ -437,16 +446,11 @@ extension OperatingMode {
437
446
task ( )
438
447
}
439
448
case . synchronous:
440
- // if for some reason, we're told to do all this stuff on
441
- // main, ignore it, and use the default queue. this prevents
442
- // a possible deadlock.
443
- if queue === DispatchQueue . main {
444
- OperatingMode . defaultQueue. asyncAndWait {
445
- task ( )
446
- }
447
- } else {
448
- queue. asyncAndWait { task ( ) }
449
- }
449
+ // in synchronous mode, always use our own queue to
450
+ // prevent deadlocks.
451
+ let workItem = DispatchWorkItem ( block: task)
452
+ OperatingMode . defaultQueue. asyncAndWait ( execute: workItem)
450
453
}
451
454
}
452
455
}
456
+
0 commit comments