public static Action <ImmutableEnvelope> Route(Func <string, IQueueWriter> factory, IEnvelopeStreamer serializer, ITapeStorageFactory tapes) { var events = factory(EventsQueue); var timerQueue = factory(TimerQueue); var entityQueue = factory(EntityQueue); var services = factory(ServiceQueue); var log = tapes.GetOrCreateStream(DomainLogName); return(envelope => { var data = serializer.SaveEnvelopeData(envelope); if (!log.TryAppend(data)) { throw new InvalidOperationException("Failed to record domain log"); } if (envelope.DeliverOnUtc > Current.UtcNow) { timerQueue.PutMessage(data); return; } if (envelope.Items.All(i => i.Content is ICommand <IIdentity>)) { entityQueue.PutMessage(data); return; } if (envelope.Items.All(i => i.Content is IEvent <IIdentity>)) { // we can have more than 1 entity event. // all entity events are routed to events as separate for (int i = 0; i < envelope.Items.Length; i++) { var name = envelope.EnvelopeId + "-e" + i; var copy = EnvelopeBuilder.CloneProperties(name, envelope); copy.AddItem(envelope.Items[i]); events.PutMessage(serializer.SaveEnvelopeData(copy.Build())); } return; } if (envelope.Items.Length != 1) { throw new InvalidOperationException( "Only entity commands or entity events can be batched"); } var item = envelope.Items[0].Content; if (item is IFunctionalCommand) { services.PutMessage(data); return; } if (item is IFunctionalEvent || item is ISampleEvent) { events.PutMessage(data); return; } throw new InvalidOperationException(string.Format("Unroutable message {0}", item)); }); }
void RunScheduler(CancellationToken token) { while (!token.IsCancellationRequested) { try { var date = DateTime.UtcNow; const int count = 100; List <Record> list; lock (_scheduler) { list = _scheduler.Where(r => r.DeliverOn <= date).Take(count).ToList(); } if (list.Count > 0) { foreach (var record in list) { var item = _storage.GetItem(record.Name); ImmutableEnvelope e; using (var mem = new MemoryStream()) { item.ReadInto((x, y) => y.CopyTo(mem)); e = _streamer.ReadAsEnvelopeData(mem.ToArray()); } // we need to reset the timer here. var newEnvelope = EnvelopeBuilder.CloneProperties(e.EnvelopeId + "-future", e); newEnvelope.DeliverOnUtc(DateTime.MinValue); newEnvelope.AddString("original-id", e.EnvelopeId); foreach (var message in e.Items) { newEnvelope.AddItem(message); } _target.PutMessage(_streamer.SaveEnvelopeData(newEnvelope.Build())); item.Delete(); lock (_scheduler) { _scheduler.Remove(record); } } } token.WaitHandle.WaitOne(5000); } catch (Exception ex) { Trace.WriteLine(ex); token.WaitHandle.WaitOne(2000); } } }
void LoadEventsTill(long maxVersion, bool sync, ToolStripItem sender) { var context = TaskScheduler.FromCurrentSynchronizationContext(); _domainGrid.DataSource = new[] { new { Message = "Loading..." } }; var start = sync ? _client.SyncLog(s => Log(s)) : Task.Factory.StartNew(() => { }); start.ContinueWith(t => { var list = new List <DomainLogDisplayItem>(); long maxCount; if (!Int64.TryParse(txtCount.Text, out maxCount)) { maxCount = MaxCount; } MaxCount = (int)maxCount; _client.ObserveTill(maxVersion, (int)maxCount, s => { var envelope = _serializer.ReadAsEnvelopeData(s.Data); for (int i = 0; i < envelope.Items.Length; i++) { var item = envelope.Items[i]; var session = DomainAwareAnalysis.GetCategoryNames(item); // clone batch envelopes into separate ones var clone = EnvelopeBuilder.CloneProperties(envelope.EnvelopeId + "-" + i, envelope); clone.AddItem(item.Content); list.Add(new DomainLogDisplayItem(clone.Build(), session, s.Version)); } }); return(list); }).ContinueWith(x => { if (x.Exception != null) { Log("Exception: {0}", x.Exception.Message); Trace.WriteLine(x.Exception); return; } var items = x.Result; if (items.Count > 0) { var min = items.Min(i => i.StoreIndex) - 1; _currentId = min; } _domainGrid.DataSource = items; tabControl1.SelectedTab = _domainLogTab; // paint foreach (DataGridViewRow dataGridViewRow in _domainGrid.Rows) { var disp = (DomainLogDisplayItem)dataGridViewRow.DataBoundItem; foreach (DataGridViewCell cell in dataGridViewRow.Cells) { disp.Style(cell); } } _domainGrid.Columns[0].Width = 200; _domainGrid.Columns[1].Width = 80; _domainGrid.Columns[2].Width = 90; _domainGrid.Columns[3].Width = 40; Log("Displayed {0} records starting from version {1}.", items.Count, _currentId); }, context) .ContinueWith(_ => { if (sender != null) { Invoke(new MethodInvoker(() => sender.Enabled = true)); } }); if (start.Status == TaskStatus.Created) { start.Start(); } }