public ProtocolEventDebouncer(ITimerFactory timerFactory, TimeSpan delay, TimeSpan maxDelay) { _timer = new SlidingWindowExclusiveTimer(timerFactory, delay, maxDelay, Process); // delegate for this block can't be async otherwise the shared exclusive scheduler is pointless _enqueueBlock = new ActionBlock <Tuple <TaskCompletionSource <bool>, ProtocolEvent, bool> >(tuple => { try { if (tuple.Item2 is KeyspaceProtocolEvent keyspaceEvent) { KeyspaceEventReceived(keyspaceEvent, tuple.Item3, tuple.Item1); } else { MainEventReceived(tuple.Item2, tuple.Item3, tuple.Item1); } } catch (Exception ex) { ProtocolEventDebouncer.Logger.Error("Unexpected exception in Protocol Event Debouncer while receiving events.", ex); } }, new ExecutionDataflowBlockOptions { EnsureOrdered = true, MaxDegreeOfParallelism = 1, TaskScheduler = _timer.ExclusiveScheduler }); _processQueueBlock = new ActionBlock <EventQueue>(async queue => { try { await ProtocolEventDebouncer.ProcessQueue(queue).ConfigureAwait(false); } catch (Exception ex) { ProtocolEventDebouncer.Logger.Error("Unexpected exception in Protocol Event Debouncer while processing queue.", ex); } }, new ExecutionDataflowBlockOptions { EnsureOrdered = true, MaxDegreeOfParallelism = 1 }); }