/// <summary> /// This message is sent from NEventstore after a commit is created. Commits might not be sent in the correct order however... /// </summary> /// <param name="msg"></param> private void Received(CommitNotification msg) { _cache.Cache(msg.Commit); _backlogCommitCount++; if (!_currentCheckpoint.HasValue) { HandleFirstCommitAfterStartup(msg); } else { List <OrderedCommitNotification> cachedCommits = _cache.GetCommitsAfter(_currentCheckpoint.Get()); if (cachedCommits.Count > 0) { //local cache can ensure we have all the commits in order: project them cachedCommits.ForEach(SendCommitToProjectors); _backlogCommitCount = 0; } else { //local cache can't ensure we have all the commits in order PollEventStoreWithExponentialBackoff(msg, _currentCheckpoint); } } }
/// <summary> /// The first commit we recieve can't be ordered by this actor. /// </summary> /// <param name="msg"></param> private void HandleFirstCommitAfterStartup(CommitNotification msg) { //NEventStore doesn't allow the getting of a commit prior to a checkpoint. so we cant' create the ordered commit notification, instead we just treat this commit as the head _currentCheckpoint = msg.Commit.CheckpointToken.ToSome(); //this commit is now considered the head //but tell the projectors to catchup, otherwise 1st commit is not projected Context.ActorSelection(_projectorsBroadCastRouter).Tell(new CatchUpMessage()); //tell projectors to catch up }
private void PollEventStoreWithExponentialBackoff(CommitNotification msg, Option <long> afterCheckpoint) { //we poll exponentially, on the size of the backlog of unprojected commits if (!IsPowerOfTwo((ulong)_backlogCommitCount)) { return; } //log @warning. Detected situation is entirely normal and expected, but should be rare. var currentCheckpoint = _currentCheckpoint.Map(x => x.ToString()).GetOrElse("no currentcommit"); Context.GetLogger() .Warning( "Received a commit notification (checkpoint {0}) whilst currentcheckpoint={1}. Commit couldn't be serialised via the cache so polling with @backlog count={2}", msg.Commit.CheckpointToken, currentCheckpoint, _backlogCommitCount); var eventStorePollerActor = MakeNewEventStorePollerActor(); //ask the poller to get the commits directly from the store Context.ActorSelection(eventStorePollerActor.Path) .Tell(new SendCommitAfterCurrentHeadCheckpointMessage(afterCheckpoint, _backlogCommitCount.ToSome())); }