private async Task <Dictionary <string, double> > GetUserCountByProjectIdsAsync(ICollection <Stack> stacks, string systemFilter, DateTime utcStart, DateTime utcEnd) { var scopedCacheClient = new ScopedCacheClient(_cacheClient, $"project:user-count:{utcStart.Floor(TimeSpan.FromMinutes(15)).Ticks}-{utcEnd.Floor(TimeSpan.FromMinutes(15)).Ticks}"); var projectIds = stacks.Select(s => s.ProjectId).Distinct().ToList(); var cachedTotals = await scopedCacheClient.GetAllAsync <double>(projectIds); var totals = cachedTotals.Where(kvp => kvp.Value.HasValue).ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Value); if (totals.Count == projectIds.Count) { return(totals); } var projects = cachedTotals.Where(kvp => !kvp.Value.HasValue).Select(kvp => new Project { Id = kvp.Key, OrganizationId = stacks.FirstOrDefault(s => s.ProjectId == kvp.Key)?.OrganizationId }).ToList(); var projectTerms = await _eventStats.GetNumbersTermsStatsAsync("project_id", _distinctUsersFields, utcStart, utcEnd, systemFilter, projects.BuildRetentionFilter()); // Cache all projects that have more than 10 users for 5 minutes. await scopedCacheClient.SetAllAsync(projectTerms.Terms.Where(t => t.Numbers[0] >= 10).ToDictionary(t => t.Term, t => t.Numbers[0]), TimeSpan.FromMinutes(5)); totals.AddRange(projectTerms.Terms.ToDictionary(kvp => kvp.Term, kvp => kvp.Numbers[0])); return(totals); }
private async Task <Dictionary <string, double> > GetUserCountByProjectIdsAsync(ICollection <Stack> stacks, AppFilter sf, DateTime utcStart, DateTime utcEnd) { var scopedCacheClient = new ScopedCacheClient(_cache, $"Project:user-count:{utcStart.Floor(TimeSpan.FromMinutes(15)).Ticks}-{utcEnd.Floor(TimeSpan.FromMinutes(15)).Ticks}"); var projectIds = stacks.Select(s => s.ProjectId).Distinct().ToList(); var cachedTotals = await scopedCacheClient.GetAllAsync <double>(projectIds); var totals = cachedTotals.Where(kvp => kvp.Value.HasValue).ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Value); if (totals.Count == projectIds.Count) { return(totals); } var systemFilter = new RepositoryQuery <PersistentEvent>().AppFilter(sf).DateRange(utcStart, utcEnd, (PersistentEvent e) => e.Date).Index(utcStart, utcEnd); var projects = cachedTotals.Where(kvp => !kvp.Value.HasValue).Select(kvp => new Project { Id = kvp.Key, OrganizationId = stacks.FirstOrDefault(s => s.ProjectId == kvp.Key)?.OrganizationId }).ToList(); var countResult = await _eventRepository.CountAsync(q => q.SystemFilter(systemFilter).FilterExpression(projects.BuildFilter()).AggregationsExpression("terms:(project_id cardinality:user)")); // Cache all projects that have more than 10 users for 5 minutes. var projectTerms = countResult.Aggregations.Terms <string>("terms_project_id").Buckets; var aggregations = projectTerms.ToDictionary(t => t.Key, t => t.Aggregations.Cardinality("cardinality_user").Value.GetValueOrDefault()); await scopedCacheClient.SetAllAsync(aggregations.Where(t => t.Value >= 10).ToDictionary(k => k.Key, v => v.Value), TimeSpan.FromMinutes(5)); totals.AddRange(aggregations); return(totals); }
public virtual async Task CanUseScopedCaches() { var cache = GetCacheClient(); if (cache == null) { return; } using (cache) { await cache.RemoveAllAsync(); var scopedCache1 = new ScopedCacheClient(cache, "scoped1"); var nestedScopedCache1 = new ScopedCacheClient(scopedCache1, "nested"); var scopedCache2 = new ScopedCacheClient(cache, "scoped2"); await cache.SetAsync("test", 1); await scopedCache1.SetAsync("test", 2); await nestedScopedCache1.SetAsync("test", 3); Assert.Equal(1, (await cache.GetAsync <int>("test")).Value); Assert.Equal(2, (await scopedCache1.GetAsync <int>("test")).Value); Assert.Equal(3, (await nestedScopedCache1.GetAsync <int>("test")).Value); Assert.Equal(3, (await scopedCache1.GetAsync <int>("nested:test")).Value); Assert.Equal(3, (await cache.GetAsync <int>("scoped1:nested:test")).Value); // ensure GetAllAsync returns unscoped keys Assert.Equal("test", (await scopedCache1.GetAllAsync <int>("test")).Keys.FirstOrDefault()); Assert.Equal("test", (await nestedScopedCache1.GetAllAsync <int>("test")).Keys.FirstOrDefault()); await scopedCache2.SetAsync("test", 1); var result = await scopedCache1.RemoveByPrefixAsync(String.Empty); Assert.Equal(2, result); // delete without any matching keys result = await scopedCache1.RemoveByPrefixAsync(String.Empty); Assert.Equal(0, result); Assert.False((await scopedCache1.GetAsync <int>("test")).HasValue); Assert.False((await nestedScopedCache1.GetAsync <int>("test")).HasValue); Assert.Equal(1, (await cache.GetAsync <int>("test")).Value); Assert.Equal(1, (await scopedCache2.GetAsync <int>("test")).Value); await scopedCache2.RemoveAllAsync(); Assert.False((await scopedCache1.GetAsync <int>("test")).HasValue); Assert.False((await nestedScopedCache1.GetAsync <int>("test")).HasValue); Assert.False((await scopedCache2.GetAsync <int>("test")).HasValue); Assert.Equal(1, (await cache.GetAsync <int>("test")).Value); } }