public object MutateIncoming(object Event, IEventDescriptor Descriptor, long?Position) { this.CurrentDescriptor = Descriptor; this.CurrentEvent = Event; this.CurrentPosition = Position; return(Event); }
public void Publish(IEventDescriptor info) { var allListeners = this.eventListenerFinder.CreateAllEventListeners(); allListeners = this.SortEventListeners(allListeners); foreach (var listener in allListeners) { var methodInfos = this.GetExecutableMethods(listener, info); foreach (var method in methodInfos) { var ps = method.GetParameters(); if (ps.Length == 0) { method.Invoke(listener, new object[] { }); continue; } if (ps.Length == 1) { object inputObject = this.mapper.Convert(info.EventData, ps[0].ParameterType); method.Invoke(listener, new object[] { inputObject }); continue; } } } }
public static IDictionary <String, String> ToDictionary(this IEventDescriptor descriptor) { var result = new Dictionary <String, String>(); result["Version"] = descriptor.Version.ToString(); result["EntityType"] = descriptor.EntityType; result["Timestamp"] = descriptor.Timestamp.ToString(); return(result.Merge(descriptor.Headers.ToDictionary(k => k.Key, v => v.Value))); }
public virtual IDisposable Observe(IEventDescriptor descriptor, object publisher, object observer, string methodName) { var callback = Delegate.CreateDelegate(descriptor.Type, observer, methodName); descriptor.Add.Invoke(publisher, callback); Action dispose = () => descriptor.Remove.Invoke(publisher, callback); return(dispose.ToDisposable()); }
public static IDictionary <string, string> ToDictionary(this IEventDescriptor descriptor) { var result = new Dictionary <string, string> { ["Version"] = descriptor.Version.ToString(), ["EntityType"] = descriptor.EntityType, ["Timestamp"] = descriptor.Timestamp.ToString(CultureInfo.InvariantCulture) }; return(descriptor.Headers.Merge(result)); }
public void Dispatch(Object @event, IEventDescriptor descriptor = null, long?position = null) { if (_processingQueueSize >= _maxQueueSize) { throw new SubscriptionCanceled("Processing queue overflow, too many items waiting to be processed"); } QueueTask(new Job { Event = @event, Descriptor = descriptor, Position = position, }); }
public virtual IDisposable Observe(IEventDescriptor descriptor, object publisher, object observer, string methodName) { #if !WINDOWS_UWP && !HAS_CRIPPLEDREFLECTION var callback = Delegate.CreateDelegate(descriptor.Type, observer, methodName); descriptor.Add.Invoke(publisher, callback); Action dispose = () => descriptor.Remove.Invoke(publisher, callback); return(dispose.ToDisposable()); #else throw new NotImplementedException(); #endif }
// Event mutating public Object MutateIncoming(Object Event, IEventDescriptor Descriptor, long?Position) { this.CurrentMessage = Event; _workHeaders[Defaults.DomainHeader] = Defaults.Domain.ToString(); if (Descriptor == null) { return(Event); } var headers = Descriptor.Headers; // There are certain headers that we can make note of // These will be committed to the event stream and included in all .Reply or .Publish done via this Unit Of Work // Meaning all receivers of events from the command will get information about the command's message, if they care foreach (var header in Defaults.CarryOverHeaders) { String defaultHeader; if (!headers.TryGetValue(header, out defaultHeader)) { defaultHeader = NotFound; } var workHeader = String.Format("{0}.{1}", PrefixHeader, header); _workHeaders[workHeader] = defaultHeader; } // Copy any application headers the user might have included var userHeaders = headers.Keys.Where(h => !h.Equals("CorrId", StringComparison.InvariantCultureIgnoreCase) && !h.Equals("WinIdName", StringComparison.InvariantCultureIgnoreCase) && !h.StartsWith("NServiceBus", StringComparison.InvariantCultureIgnoreCase) && !h.StartsWith("$", StringComparison.InvariantCultureIgnoreCase)); foreach (var header in userHeaders) { _workHeaders[header] = headers[header]; } return(Event); }
internal PerfEvent(ICtfEvent ctfEvent) { if (!(ctfEvent.EventDescriptor is IEventDescriptor eventDescriptor)) { throw new CtfPlaybackException("Not a valid Perf event."); } if (ctfEvent.Payload is null) { throw new CtfPlaybackException("Perf event payload is null."); } if (!(ctfEvent.Payload is CtfStructValue payload)) { throw new CtfPlaybackException("Perf event payload is not a structure."); } this.ctfEvent = ctfEvent; this.eventDescriptor = eventDescriptor; /// streamDefinedEventContext }
public ReflectionValue(object instance, string getMemberName, string setMemberName, string eventMemberName) { source = new ReflectionSource <T>(instance, getMemberName, setMemberName); memberChanged = (IEventDescriptor)instance.Reflection().FindDescriptor(eventMemberName); if (memberChanged == null) { var propertyChanged = instance as INotifyPropertyChanged; if (propertyChanged == null) { throw new ArgumentException("Not Supported"); } Disposable.Add(propertyChanged.Observe(OnPropertyChanged)); } else { Disposable.Add(memberChanged.Observe(instance, this, "OnMemberChanged")); } }
// Todo: all the logging and timing can be moved into a "Debug Dispatcher" which can be registered as the IDispatcher if the user wants private async Task Process(Object @event, IEventDescriptor descriptor = null, long?position = null) { var eventType = _mapper.GetMappedTypeFor(@event.GetType()); Stopwatch s = null; var handleContext = new HandleContext { Bus = _bus, EventDescriptor = descriptor }; using (_eventsTimer.NewContext()) { if (Logger.IsDebugEnabled) { Logger.DebugFormat("Processing event {0} at position {1}. Size of queue: {2}/{3}", eventType.FullName, position, _processingQueueSize, _maxQueueSize); } using (var childBuilder = _builder.CreateChildBuilder()) { var handlerGenericType = typeof(IHandleMessagesAsync <>).MakeGenericType(eventType); List <dynamic> handlers = childBuilder.BuildAll(handlerGenericType).ToList(); if (handlers.Count == 0) { return; } var success = false; var retry = 0; do { var uows = new ConcurrentStack <IEventUnitOfWork>(); var mutators = childBuilder.BuildAll <IEventMutator>(); if (Logger.IsDebugEnabled) { s = Stopwatch.StartNew(); } if (mutators != null && mutators.Any()) { Parallel.ForEach(mutators, _parallelOptions, mutate => { //if (Logger.IsDebugEnabled) Logger.DebugFormat("Mutating incoming event {0} with mutator {1}", eventType.FullName, mutate.GetType().FullName); @event = mutate.MutateIncoming(@event, descriptor, position); }); } await childBuilder.BuildAll <IEventUnitOfWork>().ForEachAsync(2, async(uow) => { uows.Push(uow); uow.Builder = childBuilder; await uow.Begin(); }); if (Logger.IsDebugEnabled) { s.Stop(); Logger.DebugFormat("UOW.Begin for event {0} took {1} ms", eventType.FullName, s.ElapsedMilliseconds); } try { if (Logger.IsDebugEnabled) { s.Restart(); } Func <dynamic, Task> processor = async(handler) => { using (_handlerTimer.NewContext()) { var handlerRetries = 0; var handlerSuccess = false; do { try { Stopwatch handlerWatch = null; if (Logger.IsDebugEnabled) { Logger.DebugFormat("Executing event {0} on handler {1}", eventType.FullName, handler.GetType().FullName); handlerWatch = Stopwatch.StartNew(); } var lambda = _objectInvoker.Invoker(handler, eventType); await lambda(handler, @event, handleContext); if (Logger.IsDebugEnabled) { handlerWatch.Stop(); Logger.DebugFormat("Executing event {0} on handler {1} took {2} ms", eventType.FullName, handler.GetType().FullName, handlerWatch.ElapsedMilliseconds); } handlerSuccess = true; } catch (RetryException e) { Logger.InfoFormat("Received retry signal while dispatching event {0} to {1}. Retry: {2}/3\nException: {3}", eventType.FullName, handler.FullName, handlerRetries, e); handlerRetries++; } } while (!handlerSuccess && (_maxRetries == -1 || handlerRetries <= _maxRetries)); if (!handlerSuccess) { Logger.ErrorFormat("Failed executing event {0} on handler {1}", eventType.FullName, handler.FullName); throw new RetryException(String.Format("Failed executing event {0} on handler {1}", eventType.FullName, handler.FullName)); } } }; // Run each handler in parallel (or not) (if handler ever is ASYNC can't use Parallel) if (_parallelHandlers) { await handlers.ForEachAsync(_parallelOptions.MaxDegreeOfParallelism, processor); } else { foreach (var handler in handlers) { await processor(handler); } } if (Logger.IsDebugEnabled) { s.Stop(); Logger.DebugFormat("Processing event {0} took {1} ms", eventType.FullName, s.ElapsedMilliseconds); } } catch (Exception e) { var trailingExceptions = new ConcurrentBag <Exception>(); await uows.Generate().ForEachAsync(2, async(uow) => { try { await uow.End(e); } catch (Exception endException) { trailingExceptions.Add(endException); } }); if (trailingExceptions.Any()) { var exceptions = trailingExceptions.ToList(); exceptions.Insert(0, e); e = new System.AggregateException(exceptions); } // Only log if the event has failed more than half max retries indicating a possible non-transient error if (retry > (_maxRetries / 2)) { Logger.InfoFormat("Encountered an error while processing {0}. Retry {1}/{2}\nPayload: {3}\nException details:\n{4}", eventType.FullName, retry, _maxRetries, JsonConvert.SerializeObject(@event), e); } else { Logger.DebugFormat("Encountered an error while processing {0}. Retry {1}/{2}\nPayload: {3}\nException details:\n{4}", eventType.FullName, retry, _maxRetries, JsonConvert.SerializeObject(@event), e); } _errorsMeter.Mark(); retry++; Thread.Sleep(10); continue; } // Failures when executing UOW.End `could` be transient (network or disk hicup) // A failure of 1 uow in a chain of 5 is a problem as it could create a mangled DB (partial update via one uow then crash) // So we'll just keep retrying the failing UOW forever until it succeeds. if (Logger.IsDebugEnabled) { s.Restart(); } var endSuccess = false; var endRetry = 0; while (!endSuccess) { try { await uows.Generate().ForEachAsync(2, async(uow) => { try { await uow.End(); } catch { // If it failed it needs to go back on the stack uows.Push(uow); throw; } }); endSuccess = true; } catch (Exception e) { if (endRetry > (_maxRetries / 2)) { Logger.ErrorFormat("UOW.End failure while processing event {0} - retry {1}/{3}\nException:\n{2}", eventType.FullName, retry, e, _maxRetries); } else { Logger.DebugFormat("UOW.End failure while processing event {0} - retry {1}/{3}\nException:\n{2}", eventType.FullName, retry, e, _maxRetries); } endRetry++; Thread.Sleep(50); } } if (Logger.IsDebugEnabled) { s.Stop(); Logger.DebugFormat("UOW.End for event {0} took {1} ms", eventType.FullName, s.ElapsedMilliseconds); } success = true; } while (!success && (_maxRetries == -1 || retry < _maxRetries)); if (!success) { var message = String.Format("Encountered an error while processing {0}. Ran out of retries, dropping event.\nPayload: {3}", eventType.FullName, JsonConvert.SerializeObject(@event)); if (_dropEventFatal) { Logger.Fatal(message); throw new SubscriptionCanceled(message); } Logger.Error(message); } } } _eventsMeter.Mark(); }
private IEnumerable <MethodInfo> GenerateExecutableMethods(IEventListener listener, IEventDescriptor eventInfo) { string eventType = EventTypeAttribute.GetEventType(listener); if (eventType != eventInfo.EventType) { return(Enumerable.Empty <MethodInfo>()); } return(listener.GetType() .GetMethods() .Where(method => { var ps = method.GetParameters(); return ps.Length == 0 || ps.Length == 1; }) .Where(method => { string eventName = EventNameAttribute.GetEventName(method); return eventName == eventInfo.EventName; }).ToList()); }
private IEnumerable <MethodInfo> GetExecutableMethods(IEventListener listener, IEventDescriptor eventInfo) { string cacheKey = $"{listener.GetType().FullName} @ {eventInfo.EventType}.{eventInfo.EventName}"; return(this.cache.GetOrCreate <IEnumerable <MethodInfo> >(cacheKey, () => GenerateExecutableMethods(listener, eventInfo))); }
public static IDisposable Observe(this IEventDescriptor descriptor, object publisher, object observer, string methodName) { return(Extensions.Observe(descriptor, publisher, observer, methodName)); }
public EventDescriptorNode(IEventDescriptor eventDescriptor) => _eventDescriptor = eventDescriptor;