private void OnQueueUpdated(FutureMessageNode originalFirst, DateTimeOffset?originalFirstFireTime)
        {
            // If the first element of the queue changed, cancel the queued tick and reschedule it at the new next fire time.
            if (this._queue.Count > 0)
            {
                // If the first element of the queue changed, cancel the queued tick and reschedule it at the new next fire time.
                // Also, if the priority of the first element changed, we need to reschedule the tick.
                var actualFirst = this._queue.First;
                if (actualFirst != originalFirst || actualFirst.Priority != originalFirstFireTime)
                {
                    this._cancellable.CancelIfNotNull();
                    this._cancellable = null;

                    var delay = actualFirst.Priority - DateTimeOffset.UtcNow;
                    if (delay < TimeSpan.Zero)
                    {
                        delay = TimeSpan.Zero;
                    }

                    this._cancellable = Context.System.Scheduler.ScheduleTellOnceCancelable(delay, this.Self, InternalTick.Instance, ActorRefs.NoSender);
                }
            }
            else
            {
                this._cancellable.CancelIfNotNull();
                this._cancellable = null;
            }
        }
        private void OnFutureMessage(FutureMessage evt)
        {
            var node = new FutureMessageNode(evt.Id, evt.Message, evt.ActorRef);

            if (this._map.TryAdd(evt.Id, node))
            {
                this._queue.Enqueue(node, evt.FireTime);
            }
        }
        private void OnQueueUpdated(FutureMessageNode originalFirst, DateTimeOffset?originalFirstFireTime, bool takeSnapshot)
        {
            // If the first element of the queue changed, cancel the queued tick and reschedule it at the new next fire time.
            if (this._queue.Count > 0)
            {
                // If the first element of the queue changed, cancel the queued tick and reschedule it at the new next fire time.
                // Also, if the priority of the first element changed, we need to reschedule the tick.
                var actualFirst = this._queue.First;
                if (actualFirst != originalFirst || actualFirst.Priority != originalFirstFireTime)
                {
                    this._cancellable.CancelIfNotNull();
                    this._cancellable = null;

                    var delay = actualFirst.Priority - DateTimeOffset.UtcNow;
                    if (delay < TimeSpan.Zero)
                    {
                        delay = TimeSpan.Zero;
                    }

                    this._cancellable = Context.System.Scheduler.ScheduleTellOnceCancelable(delay, this.Self, InternalTick.Instance, ActorRefs.NoSender);
                }
            }
            else
            {
                this._cancellable.CancelIfNotNull();
                this._cancellable = null;
            }

            // Take a snapshot every now and again in case this actor is shutdown and needs recovery.
            if (takeSnapshot && ++this._currentOperationCount >= this._operationCountPerSnapshot)
            {
                var messages = ImmutableList.CreateRange(this._map.Select(kv => new FutureMessage(kv.Key, kv.Value.Message, kv.Value.Priority, kv.Value.ActorRef)));
                this.SaveSnapshot(messages);
                this._currentOperationCount = 0;
            }
        }