@@ -317,13 +317,25 @@ fun Disposable.disposingPeriodicTask(name: String, startupDelay: Long, period: L
317317 return false
318318 }
319319
320- Disposer .register(this ) {
321- Log .log(logger::trace, " disposing periodic task {}" , name)
320+ // it may happen that 'this' is already disposed before registering a disposer.
321+ // for example tasks that dispose themselves. see for example startNoInsightsYetNotificationTimer,
322+ // in a matter of microseconds it may happen that the task will run and dispose itself before we had a chance to register a disposer,
323+ // if that happens the task will never be canceled.
324+ // or 'this' may be disposed very quickly by some other component.
325+ // in any case, if Disposer.register fails for any reason then cancel the task immediately, otherwise the task will never be canceled.
326+ // we send an error event, although it is not really an error because it is probably an ok flow, but maybe we want to know about
327+ // these cases and improve if necessary.
328+ try {
329+ Disposer .register(this ) {
330+ Log .log(logger::trace, " disposing periodic task {}" , name)
331+ future.cancel(true )
332+ }
333+ } catch (e: Throwable ) {
322334 future.cancel(true )
335+ Log .warnWithException(logger, e, " could not register disposer for task {}" , name)
336+ ErrorReporter .getInstance().reportError(" org.digma.scheduler.disposingPeriodicTask" , e, mapOf (" task.name" to name))
323337 }
324338 return true
325-
326-
327339}
328340
329341/* *
@@ -337,7 +349,7 @@ fun Disposable.disposingOneShotDelayedTask(name: String, delay: Long, block: ()
337349 consider this:
338350 calling disposingOneShotDelayedTask on a Disposable ,lets say a project service. and we would just register
339351 a child disposable on the project service to cancel the task.
340- if the project is closed before the task is executed the parent disposable, the service, will be disposed with all its children
352+ if the project is closed before the task is executed, the parent disposable, the service, will be disposed with all its children
341353 and the task will be canceled.
342354 but if the task did execute and the project service was not disposed yet, we are left with a disposable child that will be disposed
343355 only when the service is disposed.
@@ -347,14 +359,14 @@ fun Disposable.disposingOneShotDelayedTask(name: String, delay: Long, block: ()
347359 the solution:
348360 calling disposingOneShotDelayedTask on a Disposable project service. the parent.
349361 we create here a new disposable,the child, register it as child of the parent.
350- register the task on the child disposable and in disposingOneShotDelayedTask0 we register a child for the child.
362+ register the task on the child disposable and in disposingOneShotDelayedTaskImpl we register a child for the child.
351363 if the parent is disposed before the task is executed, the first child will be disposed, its child will be disposed and the task
352364 will be canceled.
353365 if the task executed and completed, the task itself disposes the first child, which will dispose its child. and now the parent
354366 doesn't have a leftover child.
355367
356- Notice that we execute disposingOneShotDelayedTask0 on the child disposable, its private and should only be used internally.
357- in disposingOneShotDelayedTask0 when the task completes it disposes this in the finally block.
368+ Notice that we execute disposingOneShotDelayedTaskImpl on the child disposable, its private and should only be used internally.
369+ in disposingOneShotDelayedTaskImpl when the task completes it disposes ' this' in the finally block.
358370 see unit tests:
359371 testDisposingOneShotDelayedTaskParentDisposableHasNoChildren
360372 testDisposingOneShotDelayedTaskCanceledParentDisposableHasNoChildren
@@ -404,14 +416,26 @@ private fun Disposable.disposingOneShotDelayedTaskImpl(name: String, delay: Long
404416 return false
405417 }
406418
407-
408- // this will run when parent disposable is disposed which will dispose this disposable and its children,if not disposed already.
409- Disposer .register(this ) {
410- Log .log(logger::trace, " disposing delayed task {}" , name)
419+ // it may happen that 'this' is already disposed before registering a disposer.
420+ // for example tasks that dispose themselves. see for example startNoInsightsYetNotificationTimer,
421+ // in a matter of microseconds it may happen that the task will run and dispose itself before we had a chance to register a disposer,
422+ // if that happens the task will never be canceled.
423+ // or 'this' may be disposed very quickly by some other component.
424+ // in any case, if Disposer.register fails for any reason then cancel the task immediately, otherwise the task will never be canceled.
425+ // we send an error event, although it is not really an error because it is probably an ok flow, but maybe we want to know about
426+ // these cases and improve if necessary.
427+ try {
428+ Disposer .register(this ) {
429+ Log .log(logger::trace, " disposing delayed task {}" , name)
430+ future.cancel(true )
431+ }
432+ } catch (e: Throwable ) {
411433 future.cancel(true )
434+ Log .warnWithException(logger, e, " could not register disposer for task {}" , name)
435+ ErrorReporter .getInstance().reportError(" org.digma.scheduler.disposingPeriodicTask" , e, mapOf (" task.name" to name))
412436 }
413-
414437 return true
438+
415439}
416440
417441/* *
0 commit comments