public async Task Should_update_repository_when_enqueing()
        {
            var @event = Envelope.Create <IEvent>(new ContentCreated {
                AppId = appId
            });

            var rule = CreateRule();

            var job = new RuleJob {
                Created = now
            };

            A.CallTo(() => ruleService.CreateJobsAsync(rule.RuleDef, rule.Id, @event, true))
            .Returns(new List <(RuleJob, Exception?)> {
                (job, null)
            });

            await sut.Enqueue(rule.RuleDef, rule.Id, @event);

            A.CallTo(() => ruleEventRepository.EnqueueAsync(job, now, default))
            .MustHaveHappened();

            A.CallTo(() => localCache.StartContext())
            .MustHaveHappened();
        }
Example #2
0
        public async Task Enqueue(Rule rule, Guid ruleId, Envelope <IEvent> @event)
        {
            Guard.NotNull(rule, nameof(rule));
            Guard.NotNull(@event, nameof(@event));

            using (localCache.StartContext())
            {
                var jobs = await ruleService.CreateJobsAsync(rule, ruleId, @event);

                foreach (var(job, ex) in jobs)
                {
                    if (ex != null)
                    {
                        await ruleEventRepository.EnqueueAsync(job, null);

                        await ruleEventRepository.UpdateAsync(job, new RuleJobUpdate
                        {
                            JobResult       = RuleJobResult.Failed,
                            ExecutionResult = RuleResult.Failed,
                            ExecutionDump   = ex.ToString(),
                            Finished        = job.Created
                        });
                    }
                    else
                    {
                        await ruleEventRepository.EnqueueAsync(job, job.Created);
                    }
                }
            }
        }
Example #3
0
 public async Task InvokeAsync(HttpContext context, RequestDelegate next)
 {
     using (localCache.StartContext())
     {
         await next(context);
     }
 }
Example #4
0
        private async Task RebuildManyAsync(string filter, Func <Guid, Task> action, CancellationToken ct)
        {
            using (localCache.StartContext())
            {
                var handledIds = new HashSet <Guid>();

                var worker = new ActionBlock <Guid>(action, new ExecutionDataflowBlockOptions {
                    MaxDegreeOfParallelism = 32
                });

                await eventStore.QueryAsync(async storedEvent =>
                {
                    var headers = storedEvent.Data.Headers;

                    var id = headers.AggregateId();

                    if (handledIds.Add(id))
                    {
                        await worker.SendAsync(id);
                    }
                }, filter, ct);

                worker.Complete();

                await worker.Completion;
            }
        }
 public async Task InvokeAsync(HttpContext context, ILocalCache localCache)
 {
     using (localCache.StartContext())
     {
         await next(context);
     }
 }
Example #6
0
        private async Task ProcessAsync(State currentState, CancellationToken ct)
        {
            try
            {
                currentReminder = await RegisterOrUpdateReminder("KeepAlive", TimeSpan.Zero, TimeSpan.FromMinutes(2));

                var rules = await appProvider.GetRulesAsync(DomainId.Create(Key));

                var rule = rules.Find(x => x.Id == currentState.RuleId);

                if (rule == null)
                {
                    throw new InvalidOperationException("Cannot find rule.");
                }

                using (localCache.StartContext())
                {
                    if (currentState.FromSnapshots && ruleService.CanCreateSnapshotEvents(rule.RuleDef))
                    {
                        await EnqueueFromSnapshotsAsync(rule);
                    }
                    else
                    {
                        await EnqueueFromEventsAsync(currentState, rule, ct);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                return;
            }
            catch (Exception ex)
            {
                log.LogError(ex, w => w
                             .WriteProperty("action", "runRule")
                             .WriteProperty("status", "failed")
                             .WriteProperty("ruleId", currentState.RuleId?.ToString()));
            }
            finally
            {
                if (!isStopping)
                {
                    currentState.RuleId   = null;
                    currentState.Position = null;

                    await state.WriteAsync();

                    if (currentReminder != null)
                    {
                        await UnregisterReminder(currentReminder);

                        currentReminder = null;
                    }

                    currentJobToken?.Dispose();
                    currentJobToken = null;
                }
            }
        }
Example #7
0
        public async Task Should_add_item_to_cache_when_context_exists()
        {
            using (sut.StartContext())
            {
                sut.Add("Key", 1);

                await Task.Delay(5);

                AssertCache(sut, "Key", 1, true);

                await Task.Delay(5);

                sut.Remove("Key");

                AssertCache(sut, "Key", null, false);
            }
        }
Example #8
0
        public AssetFolderResolverTests()
        {
            requestContext = Context.Anonymous(Mocks.App(appId));

            localCache.StartContext();

            sut = new AssetFolderResolver(localCache, assetQuery);
        }
Example #9
0
 public async Task Invoke(IIncomingGrainCallContext context)
 {
     if (!context.Grain.GetType().Namespace !.StartsWith("Orleans", StringComparison.OrdinalIgnoreCase))
     {
         using (localCache.StartContext())
         {
             await context.Invoke();
         }
     }
Example #10
0
        private async Task RebuildManyAsync <TState, TGrain>(string filter, CancellationToken ct) where TState : IDomainState <TState>, new()
        {
            var handledIds = new HashSet <Guid>();

            var worker = new ActionBlock <Guid>(async id =>
            {
                try
                {
                    var state = new TState
                    {
                        Version = EtagVersion.Empty
                    };

                    var persistence = store.WithSnapshotsAndEventSourcing(typeof(TGrain), id, (TState s) => state = s, e =>
                    {
                        state = state.Apply(e);

                        state.Version++;
                    });

                    await persistence.ReadAsync();
                    await persistence.WriteSnapshotAsync(state);
                }
                catch (DomainObjectNotFoundException)
                {
                    return;
                }
            },
                                                new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount * 2
            });

            using (localCache.StartContext())
            {
                await store.GetSnapshotStore <TState>().ClearAsync();

                await eventStore.QueryAsync(async storedEvent =>
                {
                    var id = storedEvent.Data.Headers.AggregateId();

                    if (handledIds.Add(id))
                    {
                        await worker.SendAsync(id, ct);
                    }
                }, filter, ct : ct);

                worker.Complete();

                await worker.Completion;
            }
        }
Example #11
0
        public virtual async Task InsertManyAsync <TState, TGrain>(IdSource source, CancellationToken ct = default) where TState : IDomainState <TState>, new()
        {
            Guard.NotNull(source);

            var worker = new ActionBlock <Guid>(async id =>
            {
                try
                {
                    var state = new TState
                    {
                        Version = EtagVersion.Empty
                    };

                    var persistence = store.WithSnapshotsAndEventSourcing(typeof(TGrain), id, (TState s) => state = s, e =>
                    {
                        state = state.Apply(e);

                        state.Version++;
                    });

                    await persistence.ReadAsync();
                    await persistence.WriteSnapshotAsync(state);
                }
                catch (DomainObjectNotFoundException)
                {
                    return;
                }
            },
                                                new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount * 2
            });

            var handledIds = new HashSet <Guid>();

            using (localCache.StartContext())
            {
                await source(new Func <Guid, Task>(async id =>
                {
                    if (handledIds.Add(id))
                    {
                        await worker.SendAsync(id, ct);
                    }
                }));

                worker.Complete();

                await worker.Completion;
            }
        }
        public async Task Should_add_item_to_cache_when_context_exists()
        {
            using (sut.StartContext())
            {
                sut.Add("Key", 1);

                await Task.Delay(5);

                var found = sut.TryGetValue("Key", out var value);

                Assert.True(found);
                Assert.Equal(1, value);

                await Task.Delay(5);

                sut.Remove("Key");

                var foundAfterRemove = sut.TryGetValue("Key", out value);

                Assert.False(foundAfterRemove);
                Assert.Null(value);
            }
        }
Example #13
0
        public async Task On(Envelope <IEvent> @event)
        {
            using (localCache.StartContext())
            {
                if (@event.Payload is AppEvent appEvent)
                {
                    var rules = await GetRulesAsync(appEvent.AppId.Id);

                    foreach (var ruleEntity in rules)
                    {
                        await EnqueueAsync(ruleEntity.RuleDef, ruleEntity.Id, @event);
                    }
                }
            }
        }
Example #14
0
        public async Task RebuildContentAsync()
        {
            using (localCache.StartContext())
            {
                await store.GetSnapshotStore <ContentState>().ClearAsync();

                await RebuildManyAsync("^content\\-", async id =>
                {
                    try
                    {
                        await RebuildAsync <ContentState, ContentGrain>(id, (e, s) => s.Apply(e));
                    }
                    catch (DomainObjectNotFoundException)
                    {
                        return;
                    }
                });
            }
        }
Example #15
0
        public virtual async Task InsertManyAsync <T, TState>(IdSource source, CancellationToken ct = default) where T : DomainObjectBase <TState> where TState : class, IDomainState <TState>, new()
        {
            Guard.NotNull(source);

            var worker = new ActionBlock <Guid>(async id =>
            {
                try
                {
                    var domainObject = (T)serviceProvider.GetService(typeof(T));

                    domainObject.Setup(id);

                    await domainObject.EnsureLoadedAsync();
                    await domainObject.RebuildStateAsync();
                }
                catch (DomainObjectNotFoundException)
                {
                    return;
                }
            },
                                                new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount * 2
            });

            var handledIds = new HashSet <Guid>();

            using (localCache.StartContext())
            {
                await source(new Func <Guid, Task>(async id =>
                {
                    if (handledIds.Add(id))
                    {
                        await worker.SendAsync(id, ct);
                    }
                }));

                worker.Complete();

                await worker.Completion;
            }
        }
Example #16
0
        private async Task InsertManyAsync <T, TState>(IAsyncEnumerable <DomainId> source, int batchSize, double errorThreshold,
                                                       CancellationToken ct = default)
            where T : DomainObject <TState> where TState : class, IDomainState <TState>, new()
        {
            var store = serviceProvider.GetRequiredService <IStore <TState> >();

            var parallelism = Environment.ProcessorCount;

            var handledIds    = new HashSet <DomainId>();
            var handlerErrors = 0;

            using (localCache.StartContext())
            {
                var workerBlock = new ActionBlock <DomainId[]>(async ids =>
                {
                    try
                    {
                        await using (var context = store.WithBatchContext(typeof(T)))
                        {
                            await context.LoadAsync(ids);

                            foreach (var id in ids)
                            {
                                try
                                {
                                    var domainObject = Factory <T, TState> .Create(serviceProvider, context);

                                    domainObject.Setup(id);

                                    await domainObject.RebuildStateAsync();
                                }
                                catch (DomainObjectNotFoundException)
                                {
                                    return;
                                }
                                catch (Exception ex)
                                {
                                    log.LogWarning(ex, w => w
                                                   .WriteProperty("reason", "CorruptData")
                                                   .WriteProperty("domainObjectId", id.ToString())
                                                   .WriteProperty("domainObjectType", typeof(T).Name));

                                    Interlocked.Increment(ref handlerErrors);
                                }
                            }
                        }
                    }
                    catch (OperationCanceledException ex)
                    {
                        // Dataflow swallows operation cancelled exception.
                        throw new AggregateException(ex);
                    }
                },
                                                               new ExecutionDataflowBlockOptions
                {
                    MaxDegreeOfParallelism = parallelism,
                    MaxMessagesPerTask     = 10,
                    BoundedCapacity        = parallelism
                });

                var batchBlock = new BatchBlock <DomainId>(batchSize, new GroupingDataflowBlockOptions
                {
                    BoundedCapacity = batchSize
                });

                batchBlock.BidirectionalLinkTo(workerBlock);

                await foreach (var id in source.WithCancellation(ct))
                {
                    if (handledIds.Add(id))
                    {
                        if (!await batchBlock.SendAsync(id, ct))
                        {
                            break;
                        }
                    }
                }

                batchBlock.Complete();

                await workerBlock.Completion;
            }

            var errorRate = (double)handlerErrors / handledIds.Count;

            if (errorRate > errorThreshold)
            {
                throw new InvalidOperationException($"Error rate of {errorRate} is above threshold {errorThreshold}.");
            }
        }
Example #17
0
        private async Task ProcessAsync(State currentState, CancellationToken ct)
        {
            try
            {
                currentReminder = await RegisterOrUpdateReminder("KeepAlive", TimeSpan.Zero, TimeSpan.FromMinutes(2));

                var rule = await appProvider.GetRuleAsync(DomainId.Create(Key), currentState.RuleId !.Value);

                if (rule == null)
                {
                    throw new DomainObjectNotFoundException(currentState.RuleId.ToString() !);
                }

                using (localCache.StartContext())
                {
                    var context = new RuleContext
                    {
                        AppId       = rule.AppId,
                        Rule        = rule.RuleDef,
                        RuleId      = rule.Id,
                        IgnoreStale = true
                    };

                    if (currentState.RunFromSnapshots && ruleService.CanCreateSnapshotEvents(context))
                    {
                        await EnqueueFromSnapshotsAsync(context, ct);
                    }
                    else
                    {
                        await EnqueueFromEventsAsync(currentState, context, ct);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                return;
            }
            catch (Exception ex)
            {
                log.LogError(ex, w => w
                             .WriteProperty("action", "runRule")
                             .WriteProperty("status", "failed")
                             .WriteProperty("ruleId", currentState.RuleId?.ToString()));
            }
            finally
            {
                if (!isStopping)
                {
                    currentState.RuleId   = null;
                    currentState.Position = null;

                    await state.WriteAsync();

                    if (currentReminder != null)
                    {
                        await UnregisterReminder(currentReminder);

                        currentReminder = null;
                    }

                    currentJobToken?.Dispose();
                    currentJobToken = null;
                }
            }
        }
Example #18
0
        private async Task InsertManyAsync <T, TState>(IStore <TState> store, IdSource source, CancellationToken ct = default) where T : DomainObject <TState> where TState : class, IDomainState <TState>, new()
        {
            var parallelism = Environment.ProcessorCount;

            const int BatchSize = 100;

            var workerBlock = new ActionBlock <DomainId[]>(async ids =>
            {
                await using (var context = store.WithBatchContext(typeof(T)))
                {
                    await context.LoadAsync(ids);

                    foreach (var id in ids)
                    {
                        try
                        {
                            var domainObject = Factory <T, TState> .Create(serviceProvider, context);

                            domainObject.Setup(id);

                            await domainObject.RebuildStateAsync();
                        }
                        catch (DomainObjectNotFoundException)
                        {
                            return;
                        }
                    }
                }
            },
                                                           new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = parallelism,
                MaxMessagesPerTask     = 1,
                BoundedCapacity        = parallelism
            });

            var batchBlock = new BatchBlock <DomainId>(BatchSize, new GroupingDataflowBlockOptions
            {
                BoundedCapacity = BatchSize
            });

            batchBlock.LinkTo(workerBlock, new DataflowLinkOptions
            {
                PropagateCompletion = true
            });

            var handledIds = new HashSet <DomainId>();

            using (localCache.StartContext())
            {
                await source(id =>
                {
                    if (handledIds.Add(id))
                    {
                        return(batchBlock.SendAsync(id, ct));
                    }

                    return(Task.CompletedTask);
                });

                batchBlock.Complete();

                await workerBlock.Completion;
            }
        }