// ReSharper disable once UnusedMethodReturnValue.Local private ValidationResult ValidateMessageProducer(FeedMessage message) { if (!_producerManager.Exists(message.ProducerId)) { LogFailure(message, "producer", message.ProducerId); return(ValidationResult.PROBLEMS_DETECTED); } var producer = _producerManager.Get(message.ProducerId); if (!producer.IsAvailable || producer.IsDisabled) { LogFailure(message, "producer", message.ProducerId); return(ValidationResult.PROBLEMS_DETECTED); } return(ValidationResult.SUCCESS); }
/// <summary> /// Handles the message received event /// </summary> /// <param name="sender">The <see cref="object"/> representation of the event sender</param> /// <param name="eventArgs">A <see cref="BasicDeliverEventArgs"/> containing event information</param> private void consumer_OnReceived(object sender, BasicDeliverEventArgs eventArgs) { if (eventArgs.Body == null || !eventArgs.Body.Any()) { var body = eventArgs.Body == null ? "null" : "empty"; ExecutionLog.LogWarning($"A message with {body} body received. Aborting message processing"); return; } var receivedAt = SdkInfo.ToEpochTime(DateTime.Now); // NOT used for GetRawMessage() var sessionName = _interest == null ? "system" : _interest.Name; string messageBody = null; FeedMessage feedMessage; IProducer producer; string messageName; try { using (var t = SdkMetricsFactory.MetricsRoot.Measure.Timer.Time(new TimerOptions { Context = "FEED", Name = "Message deserialization time", MeasurementUnit = Unit.Items })) { t.TrackUserValue(eventArgs.RoutingKey); messageBody = Encoding.UTF8.GetString(eventArgs.Body); feedMessage = _deserializer.Deserialize(new MemoryStream(eventArgs.Body)); producer = _producerManager.Get(feedMessage.ProducerId); messageName = feedMessage.GetType().Name; if (t.Elapsed.TotalMilliseconds > 300) { _keyParser.TryGetSportId(eventArgs.RoutingKey, messageName, out var sportId); var marketCounts = 0; var outcomeCounts = 0; if (feedMessage is odds_change oddsChange) { marketCounts = oddsChange.odds?.market?.Length ?? 0; outcomeCounts = oddsChange.odds?.market?.Where(w => w.outcome != null).SelectMany(list => list.outcome).Count() ?? 0; } if (feedMessage is bet_settlement betSettlement) { marketCounts = betSettlement.outcomes?.Length ?? 0; outcomeCounts = betSettlement.outcomes?.Where(w => w.Items != null).SelectMany(list => list.Items).Count() ?? 0; } ExecutionLog.LogDebug($"Deserialization of {feedMessage.GetType().Name} for {feedMessage.EventId} ({feedMessage.GeneratedAt}) and sport {sportId} took {t.Elapsed.TotalMilliseconds}ms. Markets={marketCounts}, Outcomes={outcomeCounts}"); } } if (producer.IsAvailable && !producer.IsDisabled) { FeedLog.LogInformation($"<~> {sessionName} <~> {eventArgs.RoutingKey} <~> {messageBody}"); } else { if (FeedLog.IsEnabled(LogLevel.Debug)) { FeedLog.LogDebug($"<~> {sessionName} <~> {eventArgs.RoutingKey} <~> {producer.Id}"); } } if (eventArgs.BasicProperties?.Headers != null) { feedMessage.SentAt = eventArgs.BasicProperties.Headers.ContainsKey("timestamp_in_ms") ? long.Parse(eventArgs.BasicProperties.Headers["timestamp_in_ms"].ToString()) : feedMessage.GeneratedAt; } feedMessage.ReceivedAt = receivedAt; SdkMetricsFactory.MetricsRoot.Measure.Meter.Mark(new MeterOptions { Context = "FEED", Name = "Message received" }, MetricTags.Empty, messageName); } catch (DeserializationException ex) { ExecutionLog.LogError($"Failed to parse message. RoutingKey={eventArgs.RoutingKey} Message: {messageBody}", ex); SdkMetricsFactory.MetricsRoot.Measure.Meter.Mark(new MeterOptions { Context = "FEED", Name = "Message deserialization exception" }, MetricTags.Empty, eventArgs.RoutingKey); RaiseDeserializationFailed(eventArgs.Body); return; } catch (Exception ex) { ExecutionLog.LogError($"Error consuming feed message. RoutingKey={eventArgs.RoutingKey} Message: {messageBody}", ex); SdkMetricsFactory.MetricsRoot.Measure.Meter.Mark(new MeterOptions { Context = "FEED", Name = "Exception consuming feed message" }, MetricTags.Empty, eventArgs.RoutingKey); RaiseDeserializationFailed(eventArgs.Body); return; } // send RawFeedMessage if needed try { if (producer.IsAvailable && !producer.IsDisabled) { //ExecutionLog.LogDebug($"Raw msg [{_interest}]: {feedMessage.GetType().Name} for event {feedMessage.EventId}."); var args = new RawFeedMessageEventArgs(eventArgs.RoutingKey, feedMessage, sessionName); RawFeedMessageReceived?.Invoke(this, args); } } catch (Exception e) { ExecutionLog.LogError($"Error dispatching raw message for {feedMessage.EventId}", e); } // continue normal processing if (!_producerManager.Exists(feedMessage.ProducerId)) { ExecutionLog.LogWarning($"A message for producer which is not defined was received. Producer={feedMessage.ProducerId}"); return; } if (!_useReplay && (!producer.IsAvailable || producer.IsDisabled)) { ExecutionLog.LogDebug($"A message for producer which is disabled was received. Producer={producer}, MessageType={messageName}"); return; } ExecutionLog.LogInformation($"Message received. Message=[{feedMessage}]."); if (feedMessage.IsEventRelated) { if (!string.IsNullOrEmpty(eventArgs.RoutingKey) && _keyParser.TryGetSportId(eventArgs.RoutingKey, messageName, out var sportId)) { feedMessage.SportId = sportId; } else { ExecutionLog.LogWarning($"Failed to parse the SportId from the routing key. RoutingKey={eventArgs.RoutingKey}, message=[{feedMessage}]. SportId will not be set."); } } RaiseMessageReceived(feedMessage, eventArgs.Body); }
/// <summary> /// Handles the message received event /// </summary> /// <param name="sender">The <see cref="object"/> representation of the event sender</param> /// <param name="eventArgs">A <see cref="BasicDeliverEventArgs"/> containing event information</param> private void consumer_OnReceived(object sender, BasicDeliverEventArgs eventArgs) { if (eventArgs.Body == null || !eventArgs.Body.Any()) { ExecutionLog.WarnFormat("A message with {0} body received. Aborting message processing", eventArgs.Body == null ? "null" : "empty"); return; } var receivedAt = SdkInfo.ToEpochTime(DateTime.Now); // NOT used for GetRawMessage() var sessionName = _interest == null ? "system" : _interest.Name; string messageBody = null; FeedMessage feedMessage; try { if (FeedLog.IsDebugEnabled) { messageBody = Encoding.UTF8.GetString(eventArgs.Body); FeedLog.Debug($"<~> {sessionName} <~> {eventArgs.RoutingKey} <~> {messageBody}"); } else { FeedLog.Info(eventArgs.RoutingKey); } feedMessage = _deserializer.Deserialize(new MemoryStream(eventArgs.Body)); if (eventArgs.BasicProperties?.Headers != null) { feedMessage.SentAt = eventArgs.BasicProperties.Headers.ContainsKey("timestamp_in_ms") ? long.Parse(eventArgs.BasicProperties.Headers["timestamp_in_ms"].ToString()) : feedMessage.GeneratedAt; } feedMessage.ReceivedAt = receivedAt; } catch (DeserializationException ex) { ExecutionLog.Error($"Failed to parse message. RoutingKey={eventArgs.RoutingKey} Message: {messageBody}", ex); Metric.Context("RABBIT").Meter("RabbitMqMessageReceiver->DeserializationException", Unit.Calls).Mark(); RaiseDeserializationFailed(eventArgs.Body); return; } // send RawFeedMessage if needed try { //ExecutionLog.Debug($"Raw msg [{_interest}]: {feedMessage.GetType().Name} for event {feedMessage.EventId}."); var args = new RawFeedMessageEventArgs(eventArgs.RoutingKey, feedMessage, sessionName); RawFeedMessageReceived?.Invoke(this, args); } catch (Exception e) { ExecutionLog.Error($"Error dispatching raw message for {feedMessage.EventId}", e); } // continue normal processing if (!_producerManager.Exists(feedMessage.ProducerId)) { ExecutionLog.Warn($"A message for producer which is not defined was received. Producer={feedMessage.ProducerId}"); return; } var producer = _producerManager.Get(feedMessage.ProducerId); var messageName = feedMessage.GetType().Name; if (!_useReplay && (!producer.IsAvailable || producer.IsDisabled)) { ExecutionLog.Debug($"A message for producer which is disabled was received. Producer={producer}, MessageType={messageName}"); return; } ExecutionLog.Info($"Message received. Message=[{feedMessage}]."); if (feedMessage.IsEventRelated) { URN sportId; if (!string.IsNullOrEmpty(eventArgs.RoutingKey) && _keyParser.TryGetSportId(eventArgs.RoutingKey, messageName, out sportId)) { feedMessage.SportId = sportId; } else { ExecutionLog.Warn($"Failed to parse the SportId from the routing key. RoutingKey={eventArgs.RoutingKey}, message=[{feedMessage}]. SportId will not be set."); } } Metric.Context("RABBIT").Meter("RabbitMqMessageReceiver", Unit.Items).Mark(messageName); RaiseMessageReceived(feedMessage, eventArgs.Body); }