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); }
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(); }
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(); } }
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 })); }
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); })); }
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); }
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(); } }