public async Task IncrementEventCounterTestAsync()
        {
            await RemoveDataAsync();

            await _repository.AddAsync(StackData.GenerateStack(id: TestConstants.StackId, projectId: TestConstants.ProjectId, organizationId: TestConstants.OrganizationId));

            await _client.RefreshAsync();

            var stack = await _repository.GetByIdAsync(TestConstants.StackId);

            Assert.NotNull(stack);
            Assert.Equal(0, stack.TotalOccurrences);
            Assert.Equal(DateTime.MinValue, stack.FirstOccurrence);
            Assert.Equal(DateTime.MinValue, stack.LastOccurrence);

            var utcNow = DateTime.UtcNow;
            await _repository.IncrementEventCounterAsync(TestConstants.OrganizationId, TestConstants.ProjectId, TestConstants.StackId, utcNow, utcNow, 1);

            await _client.RefreshAsync();

            stack = await _repository.GetByIdAsync(TestConstants.StackId);

            Assert.Equal(1, stack.TotalOccurrences);
            Assert.Equal(utcNow, stack.FirstOccurrence);
            Assert.Equal(utcNow, stack.LastOccurrence);

            await _repository.IncrementEventCounterAsync(TestConstants.OrganizationId, TestConstants.ProjectId, TestConstants.StackId, utcNow.SubtractDays(1), utcNow.SubtractDays(1), 1);

            await _client.RefreshAsync();

            stack = await _repository.GetByIdAsync(TestConstants.StackId);

            Assert.Equal(2, stack.TotalOccurrences);
            Assert.Equal(utcNow.SubtractDays(1), stack.FirstOccurrence);
            Assert.Equal(utcNow, stack.LastOccurrence);

            await _repository.IncrementEventCounterAsync(TestConstants.OrganizationId, TestConstants.ProjectId, TestConstants.StackId, utcNow.AddDays(1), utcNow.AddDays(1), 1);

            await _client.RefreshAsync();

            stack = await _repository.GetByIdAsync(TestConstants.StackId);

            Assert.Equal(3, stack.TotalOccurrences);
            Assert.Equal(utcNow.SubtractDays(1), stack.FirstOccurrence);
            Assert.Equal(utcNow.AddDays(1), stack.LastOccurrence);
        }
    public async Task CanIncrementEventCounterAsync()
    {
        var stack = await _repository.AddAsync(StackData.GenerateStack(projectId: TestConstants.ProjectId, organizationId: TestConstants.OrganizationId), o => o.ImmediateConsistency());

        Assert.NotNull(stack);
        Assert.Equal(0, stack.TotalOccurrences);
        Assert.True(stack.FirstOccurrence <= SystemClock.UtcNow);
        Assert.True(stack.LastOccurrence <= SystemClock.UtcNow);
        Assert.NotEqual(DateTime.MinValue, stack.CreatedUtc);
        Assert.NotEqual(DateTime.MinValue, stack.UpdatedUtc);
        Assert.Equal(stack.CreatedUtc, stack.UpdatedUtc);
        var updatedUtc = stack.UpdatedUtc;

        var utcNow = SystemClock.UtcNow;
        await _repository.IncrementEventCounterAsync(TestConstants.OrganizationId, TestConstants.ProjectId, stack.Id, utcNow, utcNow, 1);

        stack = await _repository.GetByIdAsync(stack.Id);

        Assert.Equal(1, stack.TotalOccurrences);
        Assert.Equal(utcNow, stack.FirstOccurrence);
        Assert.Equal(utcNow, stack.LastOccurrence);
        Assert.Equal(updatedUtc, stack.CreatedUtc);
        Assert.True(updatedUtc.IsBefore(stack.UpdatedUtc), $"Previous {updatedUtc}, Current: {stack.UpdatedUtc}");

        await _repository.IncrementEventCounterAsync(TestConstants.OrganizationId, TestConstants.ProjectId, stack.Id, utcNow.SubtractDays(1), utcNow.SubtractDays(1), 1);

        stack = await _repository.GetByIdAsync(stack.Id);

        Assert.Equal(2, stack.TotalOccurrences);
        Assert.Equal(utcNow.SubtractDays(1), stack.FirstOccurrence);
        Assert.Equal(utcNow, stack.LastOccurrence);

        await _repository.IncrementEventCounterAsync(TestConstants.OrganizationId, TestConstants.ProjectId, stack.Id, utcNow.AddDays(1), utcNow.AddDays(1), 1);

        stack = await _repository.GetByIdAsync(stack.Id);

        Assert.Equal(3, stack.TotalOccurrences);
        Assert.Equal(utcNow.SubtractDays(1), stack.FirstOccurrence);
        Assert.Equal(utcNow.AddDays(1), stack.LastOccurrence);
    }
        public override async Task ProcessBatchAsync(ICollection <EventContext> contexts)
        {
            var stacks = contexts.Where(c => !c.IsNew).GroupBy(c => c.Event.StackId);

            foreach (var stackGroup in stacks)
            {
                var stackContexts = stackGroup.ToList();

                try {
                    int      count   = stackContexts.Count;
                    DateTime minDate = stackContexts.Min(s => s.Event.Date.UtcDateTime);
                    DateTime maxDate = stackContexts.Max(s => s.Event.Date.UtcDateTime);
                    await _stackRepository.IncrementEventCounterAsync(stackContexts[0].Event.OrganizationId, stackContexts[0].Event.ProjectId, stackGroup.Key, minDate, maxDate, count).AnyContext();

                    // Update stacks in memory since they are used in notifications.
                    foreach (var ctx in stackContexts)
                    {
                        if (ctx.Stack.FirstOccurrence > minDate)
                        {
                            ctx.Stack.FirstOccurrence = minDate;
                        }

                        if (ctx.Stack.LastOccurrence < maxDate)
                        {
                            ctx.Stack.LastOccurrence = maxDate;
                        }

                        ctx.Stack.TotalOccurrences += count;
                    }
                } catch (Exception ex) {
                    foreach (var context in stackContexts)
                    {
                        bool cont = false;
                        try {
                            cont = HandleError(ex, context);
                        } catch {}

                        if (!cont)
                        {
                            context.SetError(ex.Message, ex);
                        }
                    }
                }
            }
        }
示例#4
0
    public async Task SaveStackUsagesAsync(bool sendNotifications = true, CancellationToken cancellationToken = default)
    {
        string occurrenceSetCacheKey = GetStackOccurrenceSetCacheKey();
        var    stackUsageSet         = await _cache.GetListAsync <(string OrganizationId, string ProjectId, string StackId)>(occurrenceSetCacheKey).AnyContext();

        if (!stackUsageSet.HasValue)
        {
            return;
        }

        foreach (var(organizationId, projectId, stackId) in stackUsageSet.Value)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                break;
            }

            var    removeFromSetTask = _cache.ListRemoveAsync(occurrenceSetCacheKey, (organizationId, projectId, stackId));
            string countCacheKey     = GetStackOccurrenceCountCacheKey(stackId);
            var    countTask         = _cache.GetAsync <long>(countCacheKey, 0);
            string minDateCacheKey   = GetStackOccurrenceMinDateCacheKey(stackId);
            var    minDateTask       = _cache.GetUnixTimeMillisecondsAsync(minDateCacheKey, SystemClock.UtcNow);
            string maxDateCacheKey   = GetStackOccurrenceMaxDateCacheKey(stackId);
            var    maxDateTask       = _cache.GetUnixTimeMillisecondsAsync(maxDateCacheKey, SystemClock.UtcNow);

            await Task.WhenAll(
                removeFromSetTask,
                countTask,
                minDateTask,
                maxDateTask
                ).AnyContext();

            int occurrenceCount = (int)countTask.Result;
            if (occurrenceCount <= 0)
            {
                await _cache.RemoveAllAsync(new[] { minDateCacheKey, maxDateCacheKey }).AnyContext();

                continue;
            }

            await Task.WhenAll(
                _cache.RemoveAllAsync(new[] { minDateCacheKey, maxDateCacheKey }),
                _cache.DecrementAsync(countCacheKey, occurrenceCount, _expireTimeout)
                ).AnyContext();

            var  occurrenceMinDate = minDateTask.Result;
            var  occurrenceMaxDate = maxDateTask.Result;
            bool shouldRetry       = false;
            try {
                if (!await _stackRepository.IncrementEventCounterAsync(organizationId, projectId, stackId, occurrenceMinDate, occurrenceMaxDate, occurrenceCount, sendNotifications).AnyContext())
                {
                    shouldRetry = true;
                    await IncrementStackUsageAsync(organizationId, projectId, stackId, occurrenceMinDate, occurrenceMaxDate, occurrenceCount).AnyContext();
                }
                else
                {
                    _logger.LogTrace("Increment event count {OccurrenceCount} for organization:{OrganizationId} project:{ProjectId} stack:{StackId} with Min Date:{OccurrenceMinDate} Max Date:{OccurrenceMaxDate}", occurrenceCount, organizationId, projectId, stackId, occurrenceMinDate, occurrenceMaxDate);
                }
            }
            catch (Exception ex) {
                _logger.LogError(ex, "Error incrementing event count for organization: {OrganizationId} project:{ProjectId} stack:{StackId}", organizationId, projectId, stackId);
                if (!shouldRetry)
                {
                    await IncrementStackUsageAsync(organizationId, projectId, stackId, occurrenceMinDate, occurrenceMaxDate, occurrenceCount).AnyContext();
                }
            }
        }
    }