internal void ResourceOnStreamEvent(object sender, StreamEventArgs streamEventArgs) { // Note that we can have only one update at time // as the current SDK's threading model calls this // method using always the same thread (per object basis) try { var deltaMessage = streamEventArgs.Update.FromJson <StreamMessage>(); var fixtureDelta = deltaMessage.GetContent <Fixture>(); _logger.InfoFormat("{0} stream update arrived", fixtureDelta); if (IsDisposing) { _logger.WarnFormat("Listener for {0} is disposing - skipping current update", _resource); return; } if (!AquireLock()) { _logger.WarnFormat("Failed to acquire lock while trying to process stream update {0}", fixtureDelta); return; } RaiseEvent(OnBeginStreamUpdateProcessing, null, fixtureDelta); if (IsDisposing) { _logger.WarnFormat("Listener for {0} is disposing - skipping current update", _resource); return; } // if there was an error from which we haven't recovered yet // it might be that with a new sequence, we might recover. // So in this case, ignore the update and grab a new // snapshot. if (IsErrored) { _logger.DebugFormat("Listener for {0} was in an error state - skipping update and grabbing a new snapshot", _resource); IsErrored = false; RetrieveAndProcessSnapshot(); return; } if (!IsSequenceValid(fixtureDelta)) { _logger.WarnFormat("Update for {0} will not be processed because sequence is not valid", fixtureDelta); // if snapshot was already processed with higher sequence no need to process this sequence // THIS should never happen!! if (fixtureDelta.Sequence <= _lastSequenceProcessedInSnapshot) { _logger.WarnFormat("Stream update {0} will be ignored because snapshot with higher sequence={1} was already processed", fixtureDelta, _lastSequenceProcessedInSnapshot); return; } SuspendAndReprocessSnapshot(); return; } bool hasEpochChanged; var epochValid = IsEpochValid(fixtureDelta, out hasEpochChanged); if (epochValid) { ProcessSnapshot(fixtureDelta, false, hasEpochChanged); RaiseEvent(OnFinishedStreamUpdateProcessing); } else { _fixtureStartTime = fixtureDelta.StartTime; if (fixtureDelta.IsMatchStatusChanged && !string.IsNullOrEmpty(fixtureDelta.MatchStatus)) { _logger.DebugFormat("{0} has changed matchStatus={1}", _resource, Enum.Parse(typeof(MatchStatus), fixtureDelta.MatchStatus)); _platformConnector.ProcessMatchStatus(fixtureDelta); RaiseEvent(OnFinishedStreamUpdateProcessing); } bool stopStreaming = true; if ((fixtureDelta.IsMatchStatusChanged && fixtureDelta.IsMatchOver) || fixtureDelta.IsDeleted) { if (fixtureDelta.IsDeleted) { ProcessFixtureDelete(fixtureDelta); } else // Match Over { stopStreaming = ProcessMatchOver(fixtureDelta); } RaiseEvent(OnFinishedStreamUpdateProcessing); if (stopStreaming) { Stop(); } return; } _logger.InfoFormat("Stream update {0} will not be processed because epoch was not valid", fixtureDelta); SuspendAndReprocessSnapshot(hasEpochChanged); return; } _logger.InfoFormat("Update fo {0} processed successfully", fixtureDelta); } catch (AggregateException ex) { int total = ex.InnerExceptions.Count; int count = 0; foreach (var innerEx in ex.InnerExceptions) { _logger.ErrorFormat("Error processing update for {0} {1} ({2}/{3})", _resource, innerEx, ++count, total); } SetErrorState(); RaiseEvent(OnError, ex); } catch (Exception ex) { _logger.Error(string.Format("Error processing update {0}", _resource), ex); SetErrorState(); RaiseEvent(OnError, ex); } finally { ReleaseLock(); } }
private void ProcessInvalidEpoch(Fixture fixtureDelta, bool hasEpochChanged) { _fixtureStartTime = fixtureDelta.StartTime ?? _fixtureStartTime; if (fixtureDelta.IsDeleted) { ProcessFixtureDelete(fixtureDelta); UpdateSupervisorState(fixtureDelta, false); StopStreaming(); return; } if (fixtureDelta.IsMatchStatusChanged) { if (!string.IsNullOrEmpty(fixtureDelta.MatchStatus)) { _logger.Debug( $"{_resource} has changed matchStatus={Enum.Parse(typeof(MatchStatus), fixtureDelta.MatchStatus)}"); try { _streamStatsActor.Tell(new UpdatePluginStatsStartMsg() { Fixture = fixtureDelta, Sequence = fixtureDelta.Sequence, IsSnapshot = false, UpdateReceivedAt = DateTime.UtcNow, PluginMethod = "ProcessMatchStatus" }); _platformConnector.ProcessMatchStatus(fixtureDelta); _streamStatsActor.Tell(new UpdatePluginStatsFinishMsg { CompletedAt = DateTime.UtcNow }); } catch (Exception ex) { var pluginError = new PluginException($"Plugin ProcessMatchStatus {fixtureDelta} error occured", ex); UpdateStatsError(pluginError); throw pluginError; } } if (fixtureDelta.IsMatchOver) { ProcessMatchOver(); StopStreaming(); return; } } //epoch change reason - aggregates LastEpochChange reasons into string like "BaseVariables,Starttime" var reason = fixtureDelta.LastEpochChangeReason != null && fixtureDelta.LastEpochChangeReason.Length > 0 ? fixtureDelta.LastEpochChangeReason.Select(x => ((EpochChangeReason)x).ToString()) .Aggregate((first, second) => $"{first}, {second}") : "Unknown"; _logger.Info( $"Stream update {fixtureDelta} has epoch change with reason {reason}, the snapshot will be processed instead."); SuspendAndReprocessSnapshot(hasEpochChanged); }