コード例 #1
0
        public Task Start(CancellationToken token)
        {
            var tasks = _serverProcesses.Select(p => p.Start(token)).ToArray();

            if (tasks.Length == 0)
            {
                throw new InvalidOperationException(string.Format("There were no instances of '{0}' registered", typeof(IEngineProcess).Name));
            }

            var names =
                _serverProcesses.Select(p => string.Format("{0}({1:X8})", p.GetType().Name, p.GetHashCode())).ToArray();

            _observer.Notify(new EngineStarted(names));

            return(Task.Factory.StartNew(() =>
            {
                var watch = Stopwatch.StartNew();
                try
                {
                    Task.WaitAll(tasks, token);
                }
                catch (OperationCanceledException)
                {}
                _observer.Notify(new EngineStopped(watch.Elapsed));
            }));
        }
コード例 #2
0
        void CleanupDispatchedEnvelope(ImmutableEnvelope envelope)
        {
            try
            {
                _manager.Memorize(envelope.EnvelopeId);
            }
            catch (ThreadAbortException)
            {
                // continue;
                throw;
            }
            catch (Exception ex)
            {
                SystemObserver.Notify(new EnvelopeCleanupFailed(ex, _dispatcherName, envelope));
            }

            try
            {
                _quarantine.TryRelease(envelope);
            }
            catch (ThreadAbortException)
            {
                // continue
                throw;
            }
            catch (Exception ex)
            {
                SystemObserver.Notify(new EnvelopeCleanupFailed(ex, _dispatcherName, envelope));
            }

            SystemObserver.Notify(new EnvelopeDispatched(envelope, _dispatcherName));
        }
コード例 #3
0
        private long ObserveWhileCan(IEnumerable <StoreRecord> records, RedirectToDynamicEvent wire, CancellationToken token)
        {
            var  watch             = Stopwatch.StartNew();
            var  count             = 0;
            long eventStoreVersion = 0;

            foreach (var record in records)
            {
                count += 1;

                if (token.IsCancellationRequested)
                {
                    return(eventStoreVersion);
                }
                if (count % 50000 == 0)
                {
                    SystemObserver.Notify("[observing]\t{0}\t{1} records in {2} seconds", this._name, count, Math.Round(watch.Elapsed.TotalSeconds, 2));
                    watch.Restart();
                }
                foreach (var message in record.Items.OfType <TEvent>())
                {
                    wire.InvokeEvent(message);
                }
                eventStoreVersion = record.StoreVersion;
            }
            return(eventStoreVersion);
        }
コード例 #4
0
        static void ObserveWhileCan(IEnumerable <StoreRecord> records, RedirectToDynamicEvent wire, CancellationToken token)
        {
            var watch = Stopwatch.StartNew();
            int count = 0;

            foreach (var record in records)
            {
                count += 1;

                if (token.IsCancellationRequested)
                {
                    return;
                }
                if (count % 50000 == 0)
                {
                    SystemObserver.Notify("Observing {0} {1}", count,
                                          Math.Round(watch.Elapsed.TotalSeconds, 2));
                    watch.Restart();
                }
                foreach (var message in record.Items)
                {
                    if (message is IEvent)
                    {
                        wire.InvokeEvent(message);
                    }
                }
            }
        }
コード例 #5
0
ファイル: AzureDocumentStore.cs プロジェクト: slav/lokad-cqrs
        private static async Task WaitForViewsToSave(string bucket, List <Task> tasks, int counter, Stopwatch sw)
        {
            SystemObserver.Notify("{0}: Added {1}({2}) records to save", bucket, tasks.Count, counter);
            await Task.WhenAll(tasks);

            sw.Stop();
            SystemObserver.Notify("{0}: Total {1}({2}) records saved in {3}", bucket, tasks.Count, counter, sw.Elapsed);
        }
コード例 #6
0
 internal void Initialize(CancellationToken token)
 {
     foreach (var process in _serverProcesses)
     {
         process.Initialize(token);
     }
     SystemObserver.Notify(new EngineInitialized());
 }
コード例 #7
0
        static void ConfigureObserver()
        {
            Trace.Listeners.Add(new ConsoleTraceListener());

            var observer = new ConsoleObserver();

            SystemObserver.Swap(observer);
            Context.SwapForDebug(s => SystemObserver.Notify(s));
        }
コード例 #8
0
 internal void Initialize()
 {
     SystemObserver.Notify(new EngineInitializationStarted());
     foreach (var process in _serverProcesses)
     {
         process.Initialize();
     }
     SystemObserver.Notify(new EngineInitialized());
 }
コード例 #9
0
        public bool TryToQuarantine(ImmutableEnvelope context, Exception ex)
        {
            // quit immediately, we don't want an endless cycle!
            //if (context.Items.Any(m => m.Content is MessageQuarantined))
            //    return true;
            var quarantined = _quarantine.TryToQuarantine(context, ex);

            try
            {
                var file = string.Format("{0:yyyy-MM-dd}-{1}-engine.txt",
                                         DateTime.UtcNow,
                                         context.EnvelopeId.ToLowerInvariant());



                var data = "";
                if (_root.Exists(file))
                {
                    using (var stream = _root.OpenRead(file))
                        using (var reader = new StreamReader(stream))
                        {
                            data = reader.ReadToEnd();
                        }
                }

                var builder = new StringBuilder(data);
                if (builder.Length == 0)
                {
                    DescribeMessage(builder, context);
                }

                builder.AppendLine("[Exception]");
                builder.AppendLine(DateTime.UtcNow.ToString(CultureInfo.InvariantCulture));
                builder.AppendLine(ex.ToString());
                builder.AppendLine();

                var text = builder.ToString();

                using (var stream = _root.OpenWrite(file))
                    using (var writer = new StreamWriter(stream))
                    {
                        writer.Write(text);
                    }

                if (quarantined)
                {
                    ReportFailure(text, context);
                }
            }
            catch (Exception x)
            {
                SystemObserver.Notify(x.ToString());
            }

            return(quarantined);
        }
コード例 #10
0
ファイル: AzureDocumentStore.cs プロジェクト: slav/lokad-cqrs
        public void WriteContents(string bucket, IEnumerable <DocumentRecord> records)
        {
            var retryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(0.5), 100);

            var directory = this._client.GetBlobDirectory(bucket);

            directory.Container.CreateIfNotExists();

            var tasks       = new List <Task>();
            var fullSw      = new Stopwatch();
            var fullCounter = 0;

            try
            {
                var counter = 0;
                var sw      = new Stopwatch();
                fullSw.Start();
                sw.Start();
                foreach (var record in records)
                {
                    var data = record.Read();
                    var blob = directory.GetBlockBlobReference(record.Key);
                    tasks.Add(AP.LongAsync.Do(async() => await blob.UploadFromByteArrayAsync(data, 0, data.Length, null, new BlobRequestOptions {
                        RetryPolicy = retryPolicy, MaximumExecutionTime = TimeSpan.FromMinutes(15), ServerTimeout = TimeSpan.FromMinutes(15)
                    }, null).ConfigureAwait(false)));
                    counter++;
                    fullCounter++;

                    if (tasks.Count == 200)
                    {
                        SystemObserver.Notify("{0}: Added {1}({2}) records to save", bucket, tasks.Count, counter);
                        Task.WaitAll(tasks.ToArray());
                        sw.Stop();
                        SystemObserver.Notify("{0}: Total {1}({2}) records saved in {3}", bucket, tasks.Count, counter, sw.Elapsed);
                        tasks.Clear();
                        sw.Restart();
                    }
                }
                SystemObserver.Notify("{0}: Added {1}({2}) records to save", bucket, tasks.Count, counter);
                Task.WaitAll(tasks.ToArray());
                sw.Stop();
                SystemObserver.Notify("{0}: Total {1}({2}) records saved in {3}", bucket, tasks.Count, counter, sw.Elapsed);
            }
            finally
            {
                fullSw.Stop();
                SystemObserver.Notify("{0}: Saved total {1} records in {2}", bucket, fullCounter, fullSw.Elapsed);
            }
        }
コード例 #11
0
ファイル: Setup.cs プロジェクト: rossmerr/lokad-cqrs
        static void CallHandlers(RedirectToCommand serviceCommands, ImmutableEnvelope aem)
        {
            var content = aem.Message;
            var watch   = Stopwatch.StartNew();

            serviceCommands.Invoke(content);
            watch.Stop();

            var seconds = watch.Elapsed.TotalSeconds;

            if (seconds > 10)
            {
                SystemObserver.Notify("[Warn]: {0} took {1:0.0} seconds", content.GetType().Name, seconds);
            }
        }
コード例 #12
0
        public static Container BuildEnvironment()
        {
            //JsConfig.DateHandler = JsonDateHandler.ISO8601;
            ConfigureObserver();
            var integrationPath = AzureSettingsProvider.GetStringOrThrow(Conventions.StorageConfigName);
            //var email = AzureSettingsProvider.GetStringOrThrow(Conventions.SmtpConfigName);


            //var core = new SmtpHandlerCore(email);
            var setup = new Setup
            {
                //Smtp = core,
                //FreeApiKey = freeApiKey,
                //WebClientUrl = clientUri,
                //HttpEndpoint = endPoint,
                //EncryptorTool = new EncryptorTool(systemKey)
            };

            if (integrationPath.StartsWith("file:"))
            {
                var path = integrationPath.Remove(0, 5);

                SystemObserver.Notify("Using store : {0}", path);

                var config = FileStorage.CreateConfig(path);
                setup.Streaming              = config.CreateStreaming();
                setup.DocumentStoreFactory   = config.CreateDocumentStore;
                setup.QueueReaderFactory     = s => config.CreateInbox(s, DecayEvil.BuildExponentialDecay(500));
                setup.QueueWriterFactory     = config.CreateQueueWriter;
                setup.AppendOnlyStoreFactory = config.CreateAppendOnlyStore;

                setup.ConfigureQueues(1, 1);

                return(setup.Build());
            }
            if (integrationPath.StartsWith("Default") || integrationPath.Equals("UseDevelopmentStorage=true", StringComparison.InvariantCultureIgnoreCase))
            {
                var config = AzureStorage.CreateConfig(integrationPath);
                setup.Streaming              = config.CreateStreaming();
                setup.DocumentStoreFactory   = config.CreateDocumentStore;
                setup.QueueReaderFactory     = s => config.CreateQueueReader(s);
                setup.QueueWriterFactory     = config.CreateQueueWriter;
                setup.AppendOnlyStoreFactory = config.CreateAppendOnlyStore;
                setup.ConfigureQueues(4, 4);
                return(setup.Build());
            }
            throw new InvalidOperationException("Unsupported environment");
        }
コード例 #13
0
ファイル: Listener.cs プロジェクト: trbngr/lokad-cqrs
        public Task Start(CancellationToken token)
        {
            var virtualDirectory = _environment.VirtualDirectory ?? "";

            if (!virtualDirectory.EndsWith("/"))
            {
                virtualDirectory += "/";
            }

            var prefix = "http://" + (_environment.OptionalHostName ?? "+") + ":" + _environment.Port +
                         virtualDirectory;


            return(Task.Factory.StartNew(() =>
            {
                try
                {
                    _listener = new HttpListener();
                    _listener.Prefixes.Add(prefix);
                    _listener.Start();
                }
                catch (HttpListenerException ex)
                {
                    if (ex.ErrorCode == 5)
                    {
                        var solution =
                            string.Format(
                                "Make sure to run as admin or reserve prefix. For reservation you can try executing as admin: netsh http add urlacl url={0} user={1}\\{2}",
                                prefix, Environment.MachineName,
                                Environment.UserName);
                        SystemObserver.Notify(new ConfigurationWarningEncountered("HttpListener can't connect to " + prefix + ". " + solution,
                                                                                  ex));
                    }
                    else
                    {
                        SystemObserver.Notify(new FailedToStartHttpListener(ex, prefix));
                    }
                }

                catch (Exception ex)
                {
                    SystemObserver.Notify(new FailedToStartHttpListener(ex, prefix));
                }
                _listener.BeginGetContext(ar => GetContext(ar, token), null);
                WaitTillAllProcessorsQuit(token);
                _listener.Stop();
            }, token));
        }
コード例 #14
0
        private void CallHandlers(IEnumerable <object> recordItems)
        {
            foreach (var e in recordItems.OfType <TEvent>())
            {
                var watch = Stopwatch.StartNew();
                this._eventHandlers.InvokeEvent(e);
                watch.Stop();

                var seconds = watch.Elapsed.TotalSeconds;

                if (seconds > 10)
                {
                    SystemObserver.Notify("[Warn] {0}\t{1}\t{2} took {3:0.0} seconds for handlers to process event {4}",
                                          this._name, this._projectionName, e.GetType().Name, seconds, e.ToString());
                }
            }
        }
コード例 #15
0
        public void Dispatch(byte[] message)
        {
            ImmutableEnvelope envelope = null;

            try
            {
                envelope = _streamer.ReadAsEnvelopeData(message);
            }
            catch (Exception ex)
            {
                // permanent quarantine for serialization problems
                _quarantine.Quarantine(message, ex);
                SystemObserver.Notify(new EnvelopeDeserializationFailed(ex, "dispatch"));
                return;
            }

            if (_manager.DoWeRemember(envelope.EnvelopeId))
            {
                SystemObserver.Notify(new EnvelopeDuplicateDiscarded(envelope.EnvelopeId));
                return;
            }


            try
            {
                _action(envelope);
                // non-essential but recommended
                CleanupDispatchedEnvelope(envelope);
            }
            catch (ThreadAbortException)
            {
                return;
            }
            catch (Exception ex)
            {
                if (_quarantine.TryToQuarantine(envelope, ex))
                {
                    SystemObserver.Notify(new EnvelopeQuarantined(ex, _dispatcherName, envelope));
                    // message quarantined. Swallow
                    return;
                }
                // if we are on a persistent queue, this will tell to retry
                throw;
            }
        }
コード例 #16
0
ファイル: AzureDocumentStore.cs プロジェクト: slav/lokad-cqrs
        public async Task WriteContentsAsync(string bucket, IEnumerable <DocumentRecord> records, CancellationToken token)
        {
            var retryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(0.5), 100);

            var directory = this._client.GetBlobDirectory(bucket);
            await directory.Container.CreateIfNotExistsAsync(token);

            var tasks       = new List <Task>();
            var fullSw      = new Stopwatch();
            var fullCounter = 0;

            try
            {
                var counter = 0;
                var sw      = new Stopwatch();
                fullSw.Start();
                sw.Start();
                foreach (var record in records)
                {
                    var data = record.Read();
                    var blob = directory.GetBlockBlobReference(record.Key);
                    tasks.Add(AP.LongAsync.Do(() => blob.UploadFromByteArrayAsync(data, 0, data.Length, null, new BlobRequestOptions {
                        RetryPolicy = retryPolicy, MaximumExecutionTime = TimeSpan.FromMinutes(15), ServerTimeout = TimeSpan.FromMinutes(15)
                    }, null, token)));
                    counter++;
                    fullCounter++;

                    if (tasks.Count < 200)
                    {
                        continue;
                    }

                    await WaitForViewsToSave(bucket, tasks, counter, sw);

                    tasks.Clear();
                    sw.Restart();
                }
                await WaitForViewsToSave(bucket, tasks, counter, sw);
            }
            finally
            {
                fullSw.Stop();
                SystemObserver.Notify("{0}: Saved total {1} records in {2}", bucket, fullCounter, fullSw.Elapsed);
            }
        }
コード例 #17
0
        public async Task WriteContentsAsync(string bucket, IEnumerable <DocumentRecord> records, CancellationToken token)
        {
            var buck = Path.Combine(this._folderPath, bucket);

            if (!Directory.Exists(buck))
            {
                Directory.CreateDirectory(buck);
            }

            var tasks       = new List <Task>();
            var fullSw      = new Stopwatch();
            var fullCounter = 0;

            var counter = 0;
            var sw      = new Stopwatch();

            fullSw.Start();
            sw.Start();
            foreach (var record in records)
            {
                var recordPath = Path.Combine(buck, record.Key);

                var path = Path.GetDirectoryName(recordPath) ?? "";
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                var data = record.Read();
                tasks.Add(AP.LongAsync.Do(() => this.SaveData(recordPath, data)));
                counter++;
                fullCounter++;
                if (tasks.Count == 1000)
                {
                    await WaitForViewsSave(bucket, tasks, counter, sw);

                    tasks.Clear();
                    sw.Restart();
                }
            }
            await WaitForViewsSave(bucket, tasks, counter, sw);

            fullSw.Stop();
            SystemObserver.Notify("{0}: Saved total {1} records in {2}", bucket, fullCounter, fullSw.Elapsed);
        }
コード例 #18
0
ファイル: DispatcherProcess.cs プロジェクト: slav/lokad-cqrs
        void ProcessMessage(MessageTransportContext context)
        {
            var dispatched = false;

            try
            {
                _dispatcher(context.Unpacked);

                dispatched = true;
            }
            catch (ThreadAbortException)
            {
                // we are shutting down. Stop immediately
                return;
            }
            catch (Exception dispatchEx)
            {
                // if the code below fails, it will just cause everything to be reprocessed later,
                // which is OK (duplication manager will handle this)

                SystemObserver.Notify(new MessageDispatchFailed(context, context.QueueName, dispatchEx));
                // quarantine is atomic with the processing
                _inbox.TryNotifyNack(context);
            }
            if (!dispatched)
            {
                return;
            }
            try
            {
                _inbox.AckMessage(context);
                // 3rd - notify.
                SystemObserver.Notify(new MessageAcked(context));
            }
            catch (ThreadAbortException)
            {
                // nothing. We are going to sleep
            }
            catch (Exception ex)
            {
                // not a big deal. Message will be processed again.
                SystemObserver.Notify(new MessageAckFailed(ex, context));
            }
        }
コード例 #19
0
        public GetEnvelopeResult TryGetMessage()
        {
            CloudQueueMessage message;

            try
            {
                message = this._queue.GetMessage(this._visibilityTimeout);
            }
            catch (ThreadAbortException)
            {
                // we are stopping
                return(GetEnvelopeResult.Empty);
            }
            catch (Exception ex)
            {
                SystemObserver.Notify(new FailedToReadMessage(ex, this._queueName));
                return(GetEnvelopeResult.Error());
            }

            if (null == message)
            {
                return(GetEnvelopeResult.Empty);
            }

            try
            {
                var unpacked = this.DownloadPackage(message);
                return(GetEnvelopeResult.Success(unpacked));
            }
            catch (StorageException ex)
            {
                SystemObserver.Notify(new FailedToAccessStorage(ex, this._queue.Name, message.Id));
                return(GetEnvelopeResult.Retry);
            }
            catch (Exception ex)
            {
                SystemObserver.Notify(new MessageInboxFailed(ex, this._queue.Name, message.Id));
                // new poison details
                this._posionQueue.Value.AddMessage(message);
                this._queue.DeleteMessage(message);
                return(GetEnvelopeResult.Retry);
            }
        }
コード例 #20
0
        public GetEnvelopeResult TryGetMessage()
        {
            FileInfo message;

            try
            {
                message = _queue.EnumerateFiles().FirstOrDefault();
            }
            catch (Exception ex)
            {
                SystemObserver.Notify(new FailedToReadMessage(ex, _queueName));
                return(GetEnvelopeResult.Error());
            }

            if (null == message)
            {
                return(GetEnvelopeResult.Empty);
            }

            try
            {
                var buffer = File.ReadAllBytes(message.FullName);

                var unpacked = new MessageTransportContext(message, buffer, _queueName);
                return(GetEnvelopeResult.Success(unpacked));
            }
            catch (IOException ex)
            {
                // this is probably sharing violation, no need to
                // scare people.
                if (!IsSharingViolation(ex))
                {
                    SystemObserver.Notify(new FailedToAccessStorage(ex, _queue.Name, message.Name));
                }
                return(GetEnvelopeResult.Retry);
            }
            catch (Exception ex)
            {
                SystemObserver.Notify(new MessageInboxFailed(ex, _queue.Name, message.FullName));
                // new poison details
                return(GetEnvelopeResult.Retry);
            }
        }
コード例 #21
0
        private async Task RebuildProjection(long eventStoreVersion, ProjectionInfo projectionInfo, IDocumentStore memoryContainer, CancellationToken cancellationToken)
        {
            await projectionInfo.Reset();

            var saveTasks = new List <Task>(projectionInfo.ViewBuckets.Length);

            foreach (var bucket in projectionInfo.ViewBuckets)
            {
                var sw = new Stopwatch();
                sw.Start();
                var contents = memoryContainer.EnumerateContents(bucket);
                var bucket1  = bucket;
                saveTasks.Add(this._targetContainer.WriteContentsAsync(bucket, contents, cancellationToken).ContinueWith(t =>
                {
                    sw.Stop();
                    SystemObserver.Notify("[good]\t{0}\t{1}\t{2:g}\tSaved View bucket {3}", this._name, projectionInfo.ProjectionName, sw.Elapsed, bucket1);
                }, cancellationToken, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Current));
            }
            await Task.WhenAll(saveTasks);

            await projectionInfo.UpdateEventStreamVersion(eventStoreVersion);
        }
コード例 #22
0
        private Task RebuildProjections(List <ProjectionInfo> needRebuild, IDocumentStore memoryContainer, CancellationToken token)
        {
            if (needRebuild.Count == 0)
            {
                return(Task.FromResult(true));
            }

            var updateTimer = new Stopwatch();

            updateTimer.Start();

            // observe projections
            var watch = Stopwatch.StartNew();

            var wire = new RedirectToDynamicEvent();

            needRebuild.ForEach(x => wire.WireToWhen(x.GetTempProjection()));

            var handlersWatch = Stopwatch.StartNew();

            var eventStoreVersion = this.ObserveWhileCan(this._eventsStore.EnumerateAllItems(0, int.MaxValue), wire, token);

            if (token.IsCancellationRequested)
            {
                SystemObserver.Notify("[warn]\t{0}\tShutdown. Aborting projections before anything was changed.", this._name);
                return(Task.FromResult(true));
            }

            var timeTotal      = watch.Elapsed.TotalSeconds;
            var handlerTicks   = handlersWatch.ElapsedTicks;
            var timeInHandlers = Math.Round(TimeSpan.FromTicks(handlerTicks).TotalSeconds, 1);

            SystemObserver.Notify("[observe]\t{2}\t{0}sec ({1}sec in handlers) - Replayed events from", Math.Round(timeTotal, 0), timeInHandlers, this._name);

            var rebuildTasks = needRebuild.Select(projectionInfo => this.RebuildProjection(eventStoreVersion, projectionInfo, memoryContainer, token));

            return(Task.WhenAll(rebuildTasks));
        }
コード例 #23
0
        public void SendEnvelope(ImmutableEnvelope envelope)
        {
            var queue = GetOutboundQueue();
            var data  = _streamer.SaveEnvelopeData(envelope);

            if (Transaction.Current == null)
            {
                queue.PutMessage(data);

                SystemObserver.Notify(new EnvelopeSent(queue.Name, envelope.EnvelopeId, false,
                                                       envelope.Items.Select(x => x.MappedType.Name).ToArray(), envelope.GetAllAttributes()));
            }
            else
            {
                var action = new CommitActionEnlistment(() =>
                {
                    queue.PutMessage(data);
                    SystemObserver.Notify(new EnvelopeSent(queue.Name, envelope.EnvelopeId, true,
                                                           envelope.Items.Select(x => x.MappedType.Name).ToArray(), envelope.GetAllAttributes()));
                });
                Transaction.Current.EnlistVolatile(action, EnlistmentOptions.None);
            }
        }
コード例 #24
0
ファイル: DispatcherProcess.cs プロジェクト: slav/lokad-cqrs
        void ReceiveMessages(CancellationToken outer)
        {
            using (var source = CancellationTokenSource.CreateLinkedTokenSource(_disposal.Token, outer))
            {
                while (true)
                {
                    MessageTransportContext context;
                    try
                    {
                        if (!_inbox.TakeMessage(source.Token, out context))
                        {
                            // we didn't retrieve queue within the token lifetime.
                            // it's time to shutdown the server
                            break;
                        }
                    }
                    catch (Exception)
                    {
                        continue;
                    }

                    try
                    {
                        ProcessMessage(context);
                    }
                    catch (ThreadAbortException)
                    {
                        // Nothing. we are being shutdown
                    }
                    catch (Exception ex)
                    {
                        var e = new DispatchRecoveryFailed(ex, context, context.QueueName);
                        SystemObserver.Notify(e);
                    }
                }
            }
        }
コード例 #25
0
        static void Observe(ITapeStream tapes, RedirectToDynamicEvent wire)
        {
            var date  = DateTime.MinValue;
            var watch = Stopwatch.StartNew();

            foreach (var record in tapes.ReadRecords(0, int.MaxValue))
            {
                var env = Streamer.ReadAsEnvelopeData(record.Data);
                if (date.Month != env.CreatedOnUtc.Month)
                {
                    date = env.CreatedOnUtc;
                    SystemObserver.Notify("Observing {0:yyyy-MM-dd} {1}", date, Math.Round(watch.Elapsed.TotalSeconds, 2));
                    watch.Restart();
                }
                foreach (var item in env.Items)
                {
                    var e = item.Content as IEvent;
                    if (e != null)
                    {
                        wire.InvokeEvent(e);
                    }
                }
            }
        }
コード例 #26
0
        public static void Rebuild(IDocumentStore targetContainer, ITapeStream stream)
        {
            var strategy = targetContainer.Strategy;
            var memory   = new MemoryStorageConfig();

            var memoryContainer = memory.CreateNuclear(strategy).Container;
            var tracked         = new ProjectionInspectingContainer(memoryContainer);

            var projections = new List <object>();

            projections.AddRange(DomainBoundedContext.Projections(tracked));
            projections.AddRange(ClientBoundedContext.Projections(tracked));
            //projections.AddRange(ApiOpsBoundedContext.Projections(tracked));

            if (tracked.Buckets.Count != projections.Count())
            {
                throw new InvalidOperationException("Count mismatch");
            }

            var storage = new NuclearStorage(targetContainer);
            var hashes  = storage.GetSingletonOrNew <ProjectionHash>().Entries;

            var memoryProjections = projections.Select((projection, i) =>
            {
                var bucketName = tracked.Buckets[i];
                var viewType   = tracked.Views[i];

                var projectionHash = GetClassHash(projection.GetType()) + "\r\n" + GetClassHash(viewType);

                bool needsRebuild = !hashes.ContainsKey(bucketName) || hashes[bucketName] != projectionHash;
                return(new
                {
                    bucketName,
                    projection,
                    hash = projectionHash,
                    needsRebuild
                });
            }).ToArray();

            foreach (var memoryProjection in memoryProjections)
            {
                if (memoryProjection.needsRebuild)
                {
                    SystemObserver.Notify("[warn] {0} needs rebuild", memoryProjection.bucketName);
                }
                else
                {
                    SystemObserver.Notify("[good] {0} is up-to-date", memoryProjection.bucketName);
                }
            }


            var needRebuild = memoryProjections.Where(x => x.needsRebuild).ToArray();

            if (needRebuild.Length == 0)
            {
                return;
            }



            var watch = Stopwatch.StartNew();

            var wire = new RedirectToDynamicEvent();

            needRebuild.ForEach(x => wire.WireToWhen(x.projection));


            var handlersWatch = Stopwatch.StartNew();

            Observe(stream, wire);
            var timeTotal      = watch.Elapsed.TotalSeconds;
            var handlerTicks   = handlersWatch.ElapsedTicks;
            var timeInHandlers = Math.Round(TimeSpan.FromTicks(handlerTicks).TotalSeconds, 1);

            Console.WriteLine("Total Elapsed: {0}sec ({1}sec in handlers)", Math.Round(timeTotal, 0), timeInHandlers);


            // delete projections that were rebuilt
            var bucketNames = needRebuild.Select(x => x.bucketName).ToArray();

            foreach (var name in bucketNames)
            {
                targetContainer.Reset(name);

                var contents = memoryContainer.EnumerateContents(name);
                targetContainer.WriteContents(name, contents);
            }

            var allBuckets = new HashSet <string>(memoryProjections.Select(p => p.bucketName));
            var obsolete   = hashes.Keys.Where(s => !allBuckets.Contains(s)).ToArray();

            foreach (var name in obsolete)
            {
                SystemObserver.Notify("[warn] {0} is obsolete", name);
                targetContainer.Reset(name);
            }
            storage.UpdateSingletonEnforcingNew <ProjectionHash>(x =>
            {
                x.Entries.Clear();

                foreach (var prj in memoryProjections)
                {
                    x.Entries[prj.bucketName] = prj.hash;
                }
            });
        }
コード例 #27
0
        public static void Rebuild(CancellationToken token, IDocumentStore targetContainer, MessageStore stream, Func <IDocumentStore, IEnumerable <object> > projectors)
        {
            var strategy = targetContainer.Strategy;
            var memory   = new MemoryStorageConfig();

            var memoryContainer = memory.CreateNuclear(strategy).Container;
            var tracked         = new ProjectionInspectingStore(memoryContainer);

            var projections = new List <object>();

            projections.AddRange(projectors(tracked));

            if (tracked.Projections.Count != projections.Count())
            {
                throw new InvalidOperationException("Count mismatch");
            }
            tracked.ValidateSanity();

            var storage         = new NuclearStorage(targetContainer);
            var persistedHashes = new Dictionary <string, string>();
            var name            = "domain";

            storage.GetEntity <ProjectionHash>(name).IfValue(v => persistedHashes = v.BucketHashes);

            var activeMemoryProjections = projections.Select((projection, i) =>
            {
                var proj       = tracked.Projections[i];
                var bucketName = proj.StoreBucket;
                var viewType   = proj.EntityType;

                var projectionHash =
                    "Global change on 2012-08-24\r\n" +
                    GetClassHash(projection.GetType()) +
                    "\r\n " + GetClassHash(viewType) + "\r\n" + GetClassHash(strategy.GetType());

                bool needsRebuild = !persistedHashes.ContainsKey(bucketName) || persistedHashes[bucketName] != projectionHash;
                return(new
                {
                    bucketName,
                    projection,
                    hash = projectionHash,
                    needsRebuild
                });
            }).ToArray();

            foreach (var memoryProjection in activeMemoryProjections)
            {
                if (memoryProjection.needsRebuild)
                {
                    SystemObserver.Notify("[warn] {0} needs rebuild", memoryProjection.bucketName);
                }
                else
                {
                    SystemObserver.Notify("[good] {0} is up-to-date", memoryProjection.bucketName);
                }
            }


            var needRebuild = activeMemoryProjections.Where(x => x.needsRebuild).ToArray();

            if (needRebuild.Length == 0)
            {
                return;
            }


            var watch = Stopwatch.StartNew();

            var wire = new RedirectToDynamicEvent();

            needRebuild.ForEach(x => wire.WireToWhen(x.projection));


            var handlersWatch = Stopwatch.StartNew();



            ObserveWhileCan(stream.EnumerateAllItems(0, int.MaxValue), wire, token);

            if (token.IsCancellationRequested)
            {
                SystemObserver.Notify("[warn] Aborting projections before anything was changed");
                return;
            }

            var timeTotal      = watch.Elapsed.TotalSeconds;
            var handlerTicks   = handlersWatch.ElapsedTicks;
            var timeInHandlers = Math.Round(TimeSpan.FromTicks(handlerTicks).TotalSeconds, 1);

            SystemObserver.Notify("Total Elapsed: {0}sec ({1}sec in handlers)", Math.Round(timeTotal, 0), timeInHandlers);


            // update projections that need rebuild
            foreach (var b in needRebuild)
            {
                // server might shut down the process soon anyway, but we'll be
                // in partially consistent mode (not all projections updated)
                // so at least we blow up between projection buckets
                token.ThrowIfCancellationRequested();

                var bucketName = b.bucketName;
                var bucketHash = b.hash;

                // wipe contents
                targetContainer.Reset(bucketName);
                // write new versions
                var contents = memoryContainer.EnumerateContents(bucketName);
                targetContainer.WriteContents(bucketName, contents);

                // update hash
                storage.UpdateEntityEnforcingNew <ProjectionHash>(name, x =>
                {
                    x.BucketHashes[bucketName] = bucketHash;
                });

                SystemObserver.Notify("[good] Updated View bucket {0}.{1}", name, bucketName);
            }

            // Clean up obsolete views
            var allBuckets      = new HashSet <string>(activeMemoryProjections.Select(p => p.bucketName));
            var obsoleteBuckets = persistedHashes.Where(s => !allBuckets.Contains(s.Key)).ToArray();

            foreach (var hash in obsoleteBuckets)
            {
                // quit at this stage without any bad side effects
                if (token.IsCancellationRequested)
                {
                    return;
                }

                var bucketName = hash.Key;
                SystemObserver.Notify("[warn] {0} is obsolete", bucketName);
                targetContainer.Reset(bucketName);

                storage.UpdateEntityEnforcingNew <ProjectionHash>(name, x => x.BucketHashes.Remove(bucketName));

                SystemObserver.Notify("[good] Cleaned up obsolete view bucket {0}.{1}", name, bucketName);
            }
        }
コード例 #28
0
ファイル: Program.cs プロジェクト: deke/lokad-cqrs
        static void Main(string[] args)
        {
            ConfigureObserver();

            var settings = LoadSettings();

            foreach (var setting in settings)
            {
                SystemObserver.Notify("[{0}] = {1}", setting.Key, setting.Value);
            }

            var setup = new SetupClassThatReplacesIoCContainerFramework();

            var integrationPath = settings["DataPath"];

            if (integrationPath.StartsWith("file:"))
            {
                var path   = integrationPath.Remove(0, 5);
                var config = FileStorage.CreateConfig(path);
                setup.Streaming         = config.CreateStreaming();
                setup.Tapes             = config.CreateTape;
                setup.Docs              = config.CreateNuclear(setup.Strategy).Container;
                setup.CreateInbox       = s => config.CreateInbox(s);
                setup.CreateQueueWriter = config.CreateQueueWriter;
            }
            else if (integrationPath.StartsWith("azure:"))
            {
                var path   = integrationPath.Remove(0, 6);
                var config = AzureStorage.CreateConfig(path);
                setup.Streaming         = config.CreateStreaming();
                setup.Tapes             = config.CreateTape;
                setup.Docs              = config.CreateNuclear(setup.Strategy).Container;
                setup.CreateInbox       = s => config.CreateInbox(s);
                setup.CreateQueueWriter = config.CreateQueueWriter;
            }
            else
            {
                throw new InvalidOperationException("Unsupperted environment");
            }
            var components = setup.AssembleComponents();


            var stream = setup.Tapes(Topology.TapesContainer).GetOrCreateStream(Topology.DomainLogName);

            StartupProjectionRebuilder.Rebuild(components.Setup.Docs, stream);
            using (var cts = new CancellationTokenSource())
                using (var engine = components.Builder.Build())
                {
                    var task = engine.Start(cts.Token);

                    var version         = ConfigurationManager.AppSettings.Get("appharbor.commit_id");
                    var instanceStarted = new InstanceStarted(version, "engine", Process.GetCurrentProcess().ProcessName);
                    components.Simple.SendOne(instanceStarted);

                    //startupMessages.ForEach(c => components.Sender.SendCommandsAsBatch(new ISampleCommand[] { c }));

                    Console.WriteLine(@"Press enter to stop");
                    Console.ReadLine();
                    cts.Cancel();
                    if (!task.Wait(5000))
                    {
                        Console.WriteLine(@"Terminating");
                    }
                }
        }
コード例 #29
0
        public void ChaseEvents(CancellationToken token, int chasingProjectionsDelayInMilliseconds)
        {
            SystemObserver.Notify("[chase] \t {0}\t{1}", this._name, this._projectionName);
            int errorsCount = 0;

            while (!token.IsCancellationRequested)
            {
                var errorEncountered = false;
                var eventsProcessed  = false;

                try
                {
                    var currentEventVersion = this._storeChekpoint.GetEventStreamVersion();
                    var loadedRecords       = this._eventsStore.EnumerateAllItems(currentEventVersion, EventsBatchSize);
                    foreach (var record in loadedRecords)
                    {
                        this.CallHandlers(record.Items);
                        currentEventVersion = record.StoreVersion;
                    }
                    if (currentEventVersion > this._storeChekpoint.GetEventStreamVersion())
                    {
                        var watch = Stopwatch.StartNew();

                        try
                        {
                            Task.Run(async() => await this.FlushChanges(currentEventVersion)).Wait();
                        }
                        finally
                        {
                            watch.Stop();
                            var seconds = watch.Elapsed.TotalSeconds;
                            if (seconds > 10)
                            {
                                SystemObserver.Notify("[warn] {0}\t{1}\tTook {2}s to save projection", this._name, this._projectionName, watch.Elapsed.TotalSeconds);
                            }
                        }
                        eventsProcessed = true;
                    }
                }
                catch (AggregateException x)
                {
                    foreach (var innerException in x.InnerExceptions)
                    {
                        this.Log().Error(innerException, "[Error] {0}\t{1}\tError encountered while chasing events for projection", this._name, this._projectionName);
                    }
                    errorEncountered = true;
                }
                catch (Exception x)
                {
                    this.Log().Error(x, "[Error] {0}\t{1}\tError encountered while chasing events for projection", this._name, this._projectionName);
                    errorEncountered = true;
                }

                if (errorEncountered)
                {
                    this._writer.Clear();
                    errorsCount++;
                    var errorDelay = chasingProjectionsDelayInMilliseconds * errorsCount;
                    token.WaitHandle.WaitOne(errorDelay < MaxErrorDelay ? errorDelay : MaxErrorDelay);
                }
                else
                {
                    errorsCount = 0;
                }

                if (!eventsProcessed)
                {
                    token.WaitHandle.WaitOne(chasingProjectionsDelayInMilliseconds);
                }
            }
        }
コード例 #30
0
 private void PrintProjectionsStatus(PartitionedProjectionsInfo partitionedProjections)
 {
     partitionedProjections.ReadyForUse.SelectMany(pr => pr.ViewBuckets).ForEach(b => SystemObserver.Notify("[good]\t{0} is up to date", b));
     partitionedProjections.NeedRebuild.SelectMany(pr => pr.ViewBuckets).ForEach(b => SystemObserver.Notify("[warn]\t{0} needs rebuild", b));
     partitionedProjections.Obsolete.SelectMany(pr => pr.ViewBuckets).ForEach(b => SystemObserver.Notify("[warn]\t{0} is obsolete", b));
 }