public async Task Should_cache_monthly_usage()
        {
            A.CallTo(() => inner.GetMonthlyCallsAsync(key, DateTime.Today))
            .Returns(100);

            var result1 = await sut.GetMonthlyCallsAsync(key, DateTime.Today);

            var result2 = await sut.GetMonthlyCallsAsync(key, DateTime.Today);

            Assert.Equal(100, result1);
            Assert.Equal(100, result2);

            A.CallTo(() => inner.GetMonthlyCallsAsync(key, DateTime.Today))
            .MustHaveHappened(Repeated.Exactly.Once);
        }
示例#2
0
        public async Task CheckUsagesAsync()
        {
            var today = DateTime.Today;

            foreach (var kvp in state.Value.Targets)
            {
                var target = kvp.Value;

                var from = GetFromDate(today, target.NumDays);

                if (!target.Triggered.HasValue || target.Triggered < from)
                {
                    var usage = await usageTracker.GetMonthlyCallsAsync(target.AppId.Id.ToString(), today);

                    var limit = kvp.Value.Limits;

                    if (usage > limit)
                    {
                        kvp.Value.Triggered = today;

                        var @event = new AppUsageExceeded
                        {
                            AppId        = target.AppId,
                            CallsCurrent = usage,
                            CallsLimit   = limit,
                            RuleId       = kvp.Key
                        };

                        await state.WriteEventAsync(Envelope.Create <IEvent>(@event));
                    }
                }
            }

            await state.WriteAsync();
        }
示例#3
0
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var appFeature = context.HttpContext.Features.Get <IAppFeature>();

            if (appFeature?.App != null && FilterDefinition.Weight > 0)
            {
                var plan = appPlanProvider.GetPlanForApp(appFeature.App);

                var usage = await usageTracker.GetMonthlyCallsAsync(appFeature.App.Id.ToString(), DateTime.Today);

                if (plan.MaxApiCalls >= 0 && usage > plan.MaxApiCalls * 1.1)
                {
                    context.Result = new StatusCodeResult(429);
                    return;
                }

                var stopWatch = Stopwatch.StartNew();

                try
                {
                    await next();
                }
                finally
                {
                    stopWatch.Stop();

                    await usageTracker.TrackAsync(appFeature.App.Id.ToString(), FilterDefinition.Weight, stopWatch.ElapsedMilliseconds);
                }
            }
            else
            {
                await next();
            }
        }
示例#4
0
        public ApiCostsFilterTests()
        {
            actionContext =
                new ActionExecutingContext(
                    new ActionContext(httpContext, new RouteData(),
                                      new ActionDescriptor()),
                    new List <IFilterMetadata>(), new Dictionary <string, object>(), null);

            A.CallTo(() => actionContextAccessor.ActionContext)
            .Returns(actionContext);

            A.CallTo(() => appPlansProvider.GetPlan(null))
            .Returns(appPlan);

            A.CallTo(() => appPlansProvider.GetPlanForApp(appEntity))
            .Returns(appPlan);

            A.CallTo(() => appPlan.MaxApiCalls)
            .ReturnsLazily(x => apiCallsMax);

            A.CallTo(() => usageTracker.GetMonthlyCallsAsync(A <string> .Ignored, DateTime.Today))
            .ReturnsLazily(x => Task.FromResult(apiCallsCurrent));

            next = () =>
            {
                isNextCalled = true;

                return(Task.FromResult <ActionExecutedContext?>(null));
            };

            sut = new ApiCostsFilter(appLogStore, appPlansProvider, clock, usageTracker);
        }
        public async Task <IActionResult> GetMonthlyCalls(string app)
        {
            var count = await usageTracker.GetMonthlyCallsAsync(App.Id.ToString(), DateTime.Today);

            var plan = appPlanProvider.GetPlanForApp(App);

            return(Ok(new CurrentCallsDto {
                Count = count, MaxAllowed = plan.MaxApiCalls
            }));
        }
示例#6
0
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            context.HttpContext.Features.Set <IApiCostsFeature>(FilterDefinition);

            var app = context.HttpContext.Context().App;

            if (app != null)
            {
                var appId = app.Id.ToString();

                if (FilterDefinition.Weight > 0)
                {
                    using (Profiler.Trace("CheckUsage"))
                    {
                        var plan = appPlansProvider.GetPlanForApp(app);

                        var usage = await usageTracker.GetMonthlyCallsAsync(appId, DateTime.Today);

                        if (plan?.MaxApiCalls >= 0 && usage > plan.MaxApiCalls * 1.1)
                        {
                            context.Result = new StatusCodeResult(429);
                            return;
                        }
                    }
                }

                var watch = ValueStopwatch.StartNew();

                try
                {
                    await next();
                }
                finally
                {
                    var elapsedMs = watch.Stop();

                    await appLogStore.LogAsync(app.Id, clock.GetCurrentInstant(),
                                               context.HttpContext.Request.Method,
                                               context.HttpContext.Request.Path,
                                               context.HttpContext.User.OpenIdSubject(),
                                               context.HttpContext.User.OpenIdClientId(),
                                               elapsedMs,
                                               FilterDefinition.Weight);

                    if (FilterDefinition.Weight > 0)
                    {
                        await usageTracker.TrackAsync(appId, context.HttpContext.User.OpenIdClientId(), FilterDefinition.Weight, elapsedMs);
                    }
                }
            }
            else
            {
                await next();
            }
        }
        public Task <long> GetMonthlyCallsAsync(string key, DateTime date)
        {
            Guard.NotNull(key, nameof(key));

            var cacheKey = string.Concat(key, date);

            return(Cache.GetOrCreateAsync(cacheKey, entry =>
            {
                entry.AbsoluteExpirationRelativeToNow = CacheDuration;

                return inner.GetMonthlyCallsAsync(key, date);
            }));
        }
示例#8
0
        public async Task <long> GetMonthlyCallsAsync(string key, DateTime date)
        {
            Guard.NotNull(key, nameof(key));

            var cacheKey = string.Concat(key, date);

            if (Cache.TryGetValue <long>(cacheKey, out var result))
            {
                return(result);
            }

            result = await inner.GetMonthlyCallsAsync(key, date);

            Cache.Set(cacheKey, result, CacheTime);

            return(result);
        }
示例#9
0
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var appFeature = context.HttpContext.Features.Get <IAppFeature>();

            if (appFeature?.App != null && FilterDefinition.Weight > 0)
            {
                using (Profiler.Trace("CheckUsage"))
                {
                    var plan = appPlanProvider.GetPlanForApp(appFeature.App);

                    var usage = await usageTracker.GetMonthlyCallsAsync(appFeature.App.Id.ToString(), DateTime.Today);

                    if (plan.MaxApiCalls >= 0 && usage > plan.MaxApiCalls * 1.1)
                    {
                        context.Result = new StatusCodeResult(429);
                        return;
                    }
                }

                var watch = ValueStopwatch.StartNew();

                try
                {
                    await next();
                }
                finally
                {
                    var elapsedMs = watch.Stop();

                    await usageTracker.TrackAsync(appFeature.App.Id.ToString(), context.HttpContext.User.OpenIdClientId(), FilterDefinition.Weight, elapsedMs);
                }
            }
            else
            {
                await next();
            }
        }