private void DispatchMessages(UndispatchedMessages undispatched, List <Envelope <ICommand> > deserializedCommands = null) { if (undispatched != null) { if (deserializedCommands == null) { deserializedCommands = this._serializer.Deserialize <IEnumerable <Envelope <ICommand> > >(undispatched.Commands).ToList(); } var originalCommandsCount = deserializedCommands.Count; try { while (deserializedCommands.Count > 0) { this._commandBus.Send(deserializedCommands.First()); deserializedCommands.RemoveAt(0); } } catch (Exception) { if (originalCommandsCount != deserializedCommands.Count) { undispatched.Commands = this._serializer.Serialize(deserializedCommands); try { this._context.SaveChanges(); } catch (DbUpdateConcurrencyException) { } } throw; } this._context.Set <UndispatchedMessages>().Remove(undispatched); this._context.SaveChanges(); } }
/// <summary> /// Saves the state of the process manager and publishes the commands in a resilient way. /// </summary> /// <param name="processManager">The instance to save.</param> /// <remarks> /// For explanation of the implementation details, see /// <see cref="http://go.microsoft.com/fwlink/p/?LinkID=258557"> Journey chapter 7</see>. /// </remarks> public void Save(T processManager) { var entry = context.Entry(processManager); if (entry.State == EntityState.Detached) { context.Set <T>().Add(processManager); } var commands = processManager.Commands.ToList(); UndispatchedMessages undispatched = null; if (commands.Count > 0) { // if there are pending commands to send, we store them as undispatched. undispatched = new UndispatchedMessages(processManager.Id) { Commands = serializer.Serialize(commands) }; context.Set <UndispatchedMessages>().Add(undispatched); } try { retryPolicy.ExecuteAction(() => context.SaveChanges()); } catch (DbUpdateConcurrencyException e) { throw new ConcurrencyException(e.Message, e); } try { DispatchMessages(undispatched, commands); } catch (DbUpdateConcurrencyException) { // if another thread already dispatched the messages, ignore Trace.TraceWarning("Ignoring concurrency exception while marking commands as dispatched for process manager with ID {0} in Save method.", processManager.Id); } }
public void Save(T processManager) { DbEntityEntry <T> entry = this._context.Entry(processManager); if (entry.State == EntityState.Detached) { this._context.Set <T>().Add(processManager); } List <Envelope <ICommand> > commands = processManager.Commands.ToList(); UndispatchedMessages undispatched = null; if (commands.Count > 0) { undispatched = new UndispatchedMessages(processManager.Id) { Commands = this._serializer.Serialize(commands) }; this._context.Set <UndispatchedMessages>().Add(undispatched); } try { this._context.SaveChanges(); } catch (DbUpdateConcurrencyException e) { throw new ConcurrencyException(e.Message, e); } try { this.DispatchMessages(undispatched, commands); } catch (DbUpdateConcurrencyException) { Trace.TraceWarning("Ignoring concurrency exception while marking commands as dispatched for process manager with ID {0} in Save method.", processManager.Id); } }
private void DispatchMessages(UndispatchedMessages undispatched, List <Envelope <ICommand> > deserializedCommands = null) { if (undispatched != null) { if (deserializedCommands == null) { deserializedCommands = this.serializer.Deserialize <IEnumerable <Envelope <ICommand> > >(undispatched.Commands).ToList(); } var originalCommandsCount = deserializedCommands.Count; try { while (deserializedCommands.Count > 0) { this.commandBus.Send(deserializedCommands.First()); deserializedCommands.RemoveAt(0); } } catch (Exception) { // We catch a generic exception as we don't know what implementation of ICommandBus we might be using. if (originalCommandsCount != deserializedCommands.Count) { // if we were able to send some commands, then updates the undispatched messages. undispatched.Commands = this.serializer.Serialize(deserializedCommands); try { this.context.SaveChanges(); } catch (DbUpdateConcurrencyException) { // if another thread already dispatched the messages, ignore and surface original exception instead } } throw; } // we remove all the undispatched messages for this process manager. this.context.Set <UndispatchedMessages>().Remove(undispatched); this.context.SaveChanges(); // this.retryPolicy.ExecuteAction(() => this.context.SaveChanges()); } }
public T Find(Expression <Func <T, bool> > predicate, bool includeCompleted = false) { T processManager = null; if (!includeCompleted) { processManager = this._context.Set <T>().Where(predicate.And(x => x.Completed == false)).FirstOrDefault(); } if (processManager == null) { processManager = this._context.Set <T>().Where(predicate).FirstOrDefault(); } if (processManager != null) { UndispatchedMessages undispatchedMessages = this._context.Set <UndispatchedMessages>().Find(processManager.Id); try { this.DispatchMessages(undispatchedMessages); } catch (Exception ex) { Trace.TraceWarning( "Concurrency exception while marking commands as dispatched for process manager with ID {0} in Find method.", processManager.Id); this._context.Entry(undispatchedMessages).Reload(); undispatchedMessages = this._context.Set <UndispatchedMessages>().Find(processManager.Id); this.DispatchMessages(undispatchedMessages); } if (!processManager.Completed || includeCompleted) { return(processManager); } } return(null); }