/// <remarks> /// If the event store is deployed as a cluster, it may be possible to get transient read failures. /// If an event could not be found on the event stream, try again. ///</remarks> private async Task ProcessSingleMessageAsync(string stream, Type eventType, IEnumerable handlers, BasicEventInfo eventInfo, string subscriberId) { var maxAttempts = Math.Max(_eventNotFoundRetryCount, 1); object @event = null; for (var i = 0; i < maxAttempts; i++) { if (i > 0) { await Task.Delay(_eventNotFoundRetryDelay).ConfigureAwait(false); } try { Log.Debug(_log, "{0}|{1}: Processing event {2}. Attempt: {3}", stream, subscriberId ?? "default", eventInfo.Id, i + 1); @event = await _connection.ReadEventBodyAsync(eventType, eventInfo.CanonicalEventLink).ConfigureAwait(false); if (@event != null) { break; } } catch (EventNotFoundException ex) { if (i < maxAttempts - 1) { Log.Warning(_log, "{0}|{1}: Event could not be found. Attempting to process the event again. {2}: {3}", stream, subscriberId ?? "default", eventInfo.Id, ex.Message); } else { Log.Error(_log, "{0}|{1}: Event could not be found after {2} attempts. {3}: {4}", stream, subscriberId ?? "default", i + 1, eventInfo.Id, ex.Message); return; } } catch (Exception ex) { Log.Error(_log, "{0}|{1}: Error getting message {2}: {3}", stream, subscriberId ?? "default", eventInfo.Id, ex); return; } } try { await InvokeMessageHandlersForEventMessageAsync(stream, eventType, handlers, @event, eventInfo).ConfigureAwait(false); } catch (Exception ex) { Log.Error(_log, "{0}|{1}: Error invoking message handlers for message {2}: {3}", stream, subscriberId ?? "default", eventInfo.Id, ex); } }