protected override async Task <JobResult> ProcessQueueEntryAsync(QueueEntryContext <EventNotificationWorkItem> context) { var wi = context.QueueEntry.Value; var ev = await _eventRepository.GetByIdAsync(wi.EventId).AnyContext(); if (ev == null || ev.IsDeleted) { return(JobResult.SuccessWithMessage($"Could not load event: {wi.EventId}")); } bool shouldLog = ev.ProjectId != Settings.Current.InternalProjectId; int sent = 0; _logger.Trace().Message(() => $"Process notification: project={ev.ProjectId} event={ev.Id} stack={ev.StackId}").WriteIf(shouldLog); var project = await _projectRepository.GetByIdAsync(ev.ProjectId, o => o.Cache()).AnyContext(); if (project == null) { return(JobResult.SuccessWithMessage($"Could not load project: {ev.ProjectId}.")); } _logger.Trace().Message(() => $"Loaded project: name={project.Name}").WriteIf(shouldLog); // after the first 2 occurrences, don't send a notification for the same stack more then once every 30 minutes var lastTimeSentUtc = await _cache.GetAsync <DateTime>(String.Concat("notify:stack-throttle:", ev.StackId), DateTime.MinValue).AnyContext(); if (wi.TotalOccurrences > 2 && !wi.IsRegression && lastTimeSentUtc != DateTime.MinValue && lastTimeSentUtc > SystemClock.UtcNow.AddMinutes(-30)) { _logger.Info().Message("Skipping message because of stack throttling: last sent={0} occurrences={1}", lastTimeSentUtc, wi.TotalOccurrences).WriteIf(shouldLog); return(JobResult.Success); } if (context.CancellationToken.IsCancellationRequested) { return(JobResult.Cancelled); } // don't send more than 10 notifications for a given project every 30 minutes var projectTimeWindow = TimeSpan.FromMinutes(30); string cacheKey = String.Concat("notify:project-throttle:", ev.ProjectId, "-", SystemClock.UtcNow.Floor(projectTimeWindow).Ticks); double notificationCount = await _cache.IncrementAsync(cacheKey, 1, projectTimeWindow).AnyContext(); if (notificationCount > 10 && !wi.IsRegression) { _logger.Info().Project(ev.ProjectId).Message("Skipping message because of project throttling: count={0}", notificationCount).WriteIf(shouldLog); return(JobResult.Success); } foreach (var kv in project.NotificationSettings) { var settings = kv.Value; _logger.Trace().Message(() => $"Processing notification: {kv.Key}").WriteIf(shouldLog); bool isCritical = ev.IsCritical(); bool shouldReportNewError = settings.ReportNewErrors && wi.IsNew && ev.IsError(); bool shouldReportCriticalError = settings.ReportCriticalErrors && isCritical && ev.IsError(); bool shouldReportRegression = settings.ReportEventRegressions && wi.IsRegression; bool shouldReportNewEvent = settings.ReportNewEvents && wi.IsNew; bool shouldReportCriticalEvent = settings.ReportCriticalEvents && isCritical; bool shouldReport = shouldReportNewError || shouldReportCriticalError || shouldReportRegression || shouldReportNewEvent || shouldReportCriticalEvent; _logger.Trace().Message(() => $"Settings: new error={settings.ReportNewErrors} critical error={settings.ReportCriticalErrors} regression={settings.ReportEventRegressions} new={settings.ReportNewEvents} critical={settings.ReportCriticalEvents}").WriteIf(shouldLog); _logger.Trace().Message(() => $"Should process: new error={shouldReportNewError} critical error={shouldReportCriticalError} regression={shouldReportRegression} new={shouldReportNewEvent} critical={shouldReportCriticalEvent}").WriteIf(shouldLog); var request = ev.GetRequestInfo(); // check for known bots if the user has elected to not report them if (shouldReport && !String.IsNullOrEmpty(request?.UserAgent)) { var botPatterns = project.Configuration.Settings.ContainsKey(SettingsDictionary.KnownKeys.UserAgentBotPatterns) ? project.Configuration.Settings.GetStringCollection(SettingsDictionary.KnownKeys.UserAgentBotPatterns).ToList() : new List <string>(); var info = await _parser.ParseAsync(request.UserAgent, ev.ProjectId).AnyContext(); if (info != null && info.Device.IsSpider || request.UserAgent.AnyWildcardMatches(botPatterns)) { shouldReport = false; _logger.Info().Message("Skipping because event is from a bot \"{0}\".", request.UserAgent).WriteIf(shouldLog); } } if (!shouldReport) { continue; } bool processed; switch (kv.Key) { case Project.NotificationIntegrations.Slack: processed = await _slackService.SendEventNoticeAsync(ev, project, wi.IsNew, wi.IsRegression, wi.TotalOccurrences).AnyContext(); break; default: processed = await SendEmailNotificationAsync(kv.Key, project, ev, wi, shouldLog).AnyContext(); break; } _logger.Trace().Message(() => $"Finished processing notification: {kv.Key}").WriteIf(shouldLog); if (processed) { sent++; } } // if we sent any notifications, mark the last time a notification for this stack was sent. if (sent > 0) { await _cache.SetAsync(String.Concat("notify:stack-throttle:", ev.StackId), SystemClock.UtcNow, SystemClock.UtcNow.AddMinutes(15)).AnyContext(); _logger.Info().Message("Notifications sent: event={0} stack={1} count={2}", ev.Id, ev.StackId, sent).WriteIf(shouldLog); } return(JobResult.Success); }
public Task <T> GetAsync <T>(object key) { return(_clientExt.GetAsync <T>(RedisUtils.KeyBuilder <T>(key))); }
public static async Task <T> GetAsync <T>(this ICacheClient client, string key, T defaultValue) { var cacheValue = await client.GetAsync <T>(key).AnyContext(); return(cacheValue.HasValue ? cacheValue.Value : defaultValue); }
/** <inheritDoc /> */ public TV Get(TK key) { return(_cache.GetAsync(key).GetResult()); }
public static new async Task <Player> GetAsync([NotNull] ICacheClient redis, DbRef playerRef, CancellationToken cancellationToken) => (await CacheManager.LookupOrRetrieveAsync(playerRef, redis, async(d, token) => await redis.GetAsync <Player>($"mudpie::player:{d}"), cancellationToken))?.DataObject;
public async Task <ILock> AcquireAsync(string resource, TimeSpan?timeUntilExpires = null, bool releaseOnDispose = true, CancellationToken cancellationToken = default) { bool isTraceLogLevelEnabled = _logger.IsEnabled(LogLevel.Trace); if (isTraceLogLevelEnabled) { _logger.LogTrace("AcquireLockAsync: {Resource}", resource); } bool allowLock = false; byte errors = 0; string lockId = Guid.NewGuid().ToString("N"); var sw = Stopwatch.StartNew(); do { string cacheKey = GetCacheKey(resource, SystemClock.UtcNow); try { if (isTraceLogLevelEnabled) { _logger.LogTrace("Current time: {CurrentTime} throttle: {ThrottlingPeriod} key: {Key}", SystemClock.UtcNow.ToString("mm:ss.fff"), SystemClock.UtcNow.Floor(_throttlingPeriod).ToString("mm:ss.fff"), cacheKey); } var hitCount = await _cacheClient.GetAsync <long?>(cacheKey, 0).AnyContext(); if (isTraceLogLevelEnabled) { _logger.LogTrace("Current hit count: {HitCount} max: {MaxHitsPerPeriod}", hitCount, _maxHitsPerPeriod); } if (hitCount <= _maxHitsPerPeriod - 1) { hitCount = await _cacheClient.IncrementAsync(cacheKey, 1, SystemClock.UtcNow.Ceiling(_throttlingPeriod)).AnyContext(); // make sure someone didn't beat us to it. if (hitCount <= _maxHitsPerPeriod) { allowLock = true; break; } if (isTraceLogLevelEnabled) { _logger.LogTrace("Max hits exceeded after increment for {Resource}.", resource); } } else if (isTraceLogLevelEnabled) { _logger.LogTrace("Max hits exceeded for {Resource}.", resource); } if (cancellationToken.IsCancellationRequested) { break; } var sleepUntil = SystemClock.UtcNow.Ceiling(_throttlingPeriod).AddMilliseconds(1); if (sleepUntil > SystemClock.UtcNow) { if (isTraceLogLevelEnabled) { _logger.LogTrace("Sleeping until key expires: {SleepUntil}", sleepUntil - SystemClock.UtcNow); } await SystemClock.SleepAsync(sleepUntil - SystemClock.UtcNow, cancellationToken).AnyContext(); } else { if (isTraceLogLevelEnabled) { _logger.LogTrace("Default sleep"); } await SystemClock.SleepAsync(50, cancellationToken).AnyContext(); } } catch (OperationCanceledException) { return(null); } catch (Exception ex) { _logger.LogError(ex, "Error acquiring throttled lock: name={Resource} message={Message}", resource, ex.Message); errors++; if (errors >= 3) { break; } await SystemClock.SleepSafeAsync(50, cancellationToken).AnyContext(); } } while (!cancellationToken.IsCancellationRequested); if (cancellationToken.IsCancellationRequested && isTraceLogLevelEnabled) { _logger.LogTrace("Cancellation requested"); } if (!allowLock) { return(null); } if (isTraceLogLevelEnabled) { _logger.LogTrace("Allowing lock: {Resource}", resource); } sw.Stop(); return(new DisposableLock(resource, lockId, sw.Elapsed, this, _logger, releaseOnDispose)); }
public async Task <ILock> AcquireAsync(string name, TimeSpan?lockTimeout = null, CancellationToken cancellationToken = default(CancellationToken)) { _logger.Trace("AcquireLockAsync: {name}", name); bool allowLock = false; byte errors = 0; do { string cacheKey = GetCacheKey(name, SystemClock.UtcNow); try { _logger.Trace("Current time: {0} throttle: {1} key: {2}", SystemClock.UtcNow.ToString("mm:ss.fff"), SystemClock.UtcNow.Floor(_throttlingPeriod).ToString("mm:ss.fff"), cacheKey); var hitCount = await _cacheClient.GetAsync <long?>(cacheKey, 0).AnyContext(); _logger.Trace("Current hit count: {0} max: {1}", hitCount, _maxHitsPerPeriod); if (hitCount <= _maxHitsPerPeriod - 1) { hitCount = await _cacheClient.IncrementAsync(cacheKey, 1, SystemClock.UtcNow.Ceiling(_throttlingPeriod)).AnyContext(); // make sure someone didn't beat us to it. if (hitCount <= _maxHitsPerPeriod) { allowLock = true; break; } _logger.Trace("Max hits exceeded after increment for {0}.", name); } else { _logger.Trace("Max hits exceeded for {0}.", name); } if (cancellationToken.IsCancellationRequested) { _logger.Trace("Cancellation Requested."); break; } var sleepUntil = SystemClock.UtcNow.Ceiling(_throttlingPeriod).AddMilliseconds(1); if (sleepUntil > SystemClock.UtcNow) { _logger.Trace("Sleeping until key expires: {0}", sleepUntil - SystemClock.UtcNow); await SystemClock.SleepAsync(sleepUntil - SystemClock.UtcNow, cancellationToken).AnyContext(); } else { _logger.Trace("Default sleep."); await SystemClock.SleepAsync(50, cancellationToken).AnyContext(); } } catch (OperationCanceledException) { return(null); } catch (Exception ex) { _logger.Error(ex, "Error acquiring throttled lock: name={0} message={1}", name, ex.Message); errors++; if (errors >= 3) { break; } await SystemClock.SleepAsync(50, cancellationToken).AnyContext(); } } while (!cancellationToken.IsCancellationRequested); if (cancellationToken.IsCancellationRequested) { _logger.Trace("Cancellation requested."); } if (!allowLock) { return(null); } _logger.Trace("Allowing lock: {0}", name); return(new DisposableLock(name, this, _logger)); }
public async Task CheckAsync(IDiscordMessage e) { if (e.Author.IsBot) { return; } if (experienceLock.CurrentCount == 0) { return; } try { using var scope = app.Services.CreateScope(); var services = scope.ServiceProvider; if (e is IDiscordGuildMessage guildMessage) { var key = GetContextKey(guildMessage.GuildId, e.Author.Id); if (lastTimeExpGranted .GetOrAdd(e.Author.Id, DateTime.Now) .AddMinutes(1) < DateTime.Now) { var bonusExp = MikiRandom.Next(1, 4); var expObject = new ExperienceAdded { UserId = (long)e.Author.Id, GuildId = (long)guildMessage.GuildId, Experience = bonusExp, Name = e.Author.Username, }; int currentLocalExp = await cache.GetAsync <int>(key); if (currentLocalExp == 0) { var dbContext = services.GetService <DbContext>(); var expProfile = await GetOrCreateExperienceProfileAsync( dbContext, e.Author as IDiscordGuildUser); await UpdateCacheExperienceAsync(expObject); currentLocalExp = expProfile.Experience; } currentLocalExp += bonusExp; experienceQueue.AddOrUpdate(e.Author.Id, expObject, (_, experience) => { experience.Experience += expObject.Experience; return(experience); }); int level = User.CalculateLevel(currentLocalExp); if (User.CalculateLevel(currentLocalExp - bonusExp) != level) { await LevelUpLocalAsync(e, level) .ConfigureAwait(false); } lastTimeExpGranted.AddOrUpdate( e.Author.Id, DateTime.Now, (x, d) => DateTime.Now); await UpdateCacheExperienceAsync(expObject); } } if (DateTime.Now >= this.lastDbSync + new TimeSpan(0, 1, 0)) { try { await experienceLock.WaitAsync(); Log.Message($"Applying Experience for {this.experienceQueue.Count} users"); this.lastDbSync = DateTime.Now; var context = services.GetService <DbContext>(); await UpdateGlobalDatabaseAsync(context); await UpdateLocalDatabaseAsync(context); await UpdateGuildDatabaseAsync(context); await context.SaveChangesAsync(); } catch (Exception ex) { Log.Error(ex.Message + "\n" + ex.StackTrace); sentryClient.CaptureException(ex); } finally { this.experienceQueue.Clear(); experienceLock.Release(); } } } catch (Exception ex) { Log.Error(ex); sentryClient.CaptureException(ex); } }
public void GetAsync() { _cache.GetAsync(1).Wait(); }
protected T Get(long id) => _cache.GetAsync <T>(ToKey(id)).GetAwaiter().GetResult().Value;
public Task <Client> GetAsync(string key) { return(cacheClient.GetAsync <Client>(key)); }
async Task Test <T>(ICacheClient client, T value, T value2) { string itemKey = "test"; await client.UpsertAsync(itemKey, value); Assert.True(await client.ExistsAsync(itemKey)); T i = await client.GetAsync <T>(itemKey); Assert.Equal(value, i); await client.RemoveAsync(itemKey); if (client is IExtendedCacheClient ex) { string hashKey = "test:hash"; Assert.False(await client.ExistsAsync(hashKey)); Assert.False(await ex.HashExistsAsync(hashKey, itemKey)); Assert.DoesNotContain(await ex.HashKeysAsync(hashKey), x => x == itemKey); Assert.DoesNotContain(await ex.HashValuesAsync <T>(hashKey), x => x.Equals(value)); Assert.DoesNotContain(await ex.HashGetAllAsync <T>(hashKey), x => x.Key == itemKey && x.Value.Equals(value)); Assert.NotEqual(value, await ex.HashGetAsync <T>(hashKey, itemKey)); Assert.NotEqual(1, await ex.HashLengthAsync(hashKey)); await ex.HashUpsertAsync(hashKey, itemKey, value); Assert.True(await client.ExistsAsync(hashKey)); Assert.True(await ex.HashExistsAsync(hashKey, itemKey)); Assert.Contains(await ex.HashKeysAsync(hashKey), x => x == itemKey); Assert.Contains(await ex.HashValuesAsync <T>(hashKey), x => x.Equals(value)); Assert.Contains(await ex.HashGetAllAsync <T>(hashKey), x => x.Key == itemKey && x.Value.Equals(value)); Assert.Equal(value, await ex.HashGetAsync <T>(hashKey, itemKey)); Assert.Equal(1, await ex.HashLengthAsync(hashKey)); await ex.HashUpsertAsync(hashKey, itemKey, value2); Assert.True(await client.ExistsAsync(hashKey)); Assert.True(await ex.HashExistsAsync(hashKey, itemKey)); var keys = await ex.HashKeysAsync(hashKey); Assert.Contains(keys, x => x == itemKey); var values = await ex.HashValuesAsync <T>(hashKey); Assert.Contains(values, x => x.Equals(value2)); Assert.Contains(await ex.HashGetAllAsync <T>(hashKey), x => x.Key == itemKey && x.Value.Equals(value2)); Assert.Equal(value2, await ex.HashGetAsync <T>(hashKey, itemKey)); Assert.Equal(1, await ex.HashLengthAsync(hashKey)); await ex.HashDeleteAsync(hashKey, itemKey); Assert.Equal(default, await ex.HashGetAsync <T>(hashKey, itemKey));
public async Task <IReadOnlyCollection <string> > GetAllowedUserPermissionAsync(ulong userId, ulong?guildId) { var cacheKey = CacheKey.GetUserPermissionCacheKey(guildId, userId); var cache = await _cache.GetAsync <string[]>(cacheKey); if (cache.HasValue) { return(cache.Value); } var stopwatch = Stopwatch.StartNew(); using var scope = _provider.CreateScope(); var roleRepo = scope.ServiceProvider.GetService <IRolePermissionRepository>(); var userRepo = scope.ServiceProvider.GetService <IUserPermissionRepository>(); IDiscordUser user; IReadOnlyList <PermissionGroup> userPermissions; IReadOnlyList <IDiscordRole> userRoles; if (guildId.HasValue) { var guildUser = await _client.GetGuildUserAsync(userId, guildId.Value); var guild = await _client.GetGuildAsync(guildId.Value); var roles = await guild.GetRolesAsync(); userRoles = roles.Where(r => guildUser.RoleIds.Contains(r.Id)).ToList(); user = guildUser; userPermissions = await GetPermissionGroups(guildUser, guild); } else { userRoles = new IDiscordRole[0]; user = await _client.GetUserAsync(userId); userPermissions = GetDefaultPermissions(user); } var permissions = new Dictionary <string, bool>(); void AddPermissions(IEnumerable <IPermission> newPermissions) { foreach (var permission in newPermissions) { if (!permissions.ContainsKey(permission.Name)) { permissions[permission.Name] = permission.Granted; } } } // Add the default permissions. if (userPermissions.Contains(PermissionGroup.Developer) && _defaultPermissions.TryGetValue(PermissionGroup.Developer, out var newPermissions)) { AddPermissions(newPermissions); } if (userPermissions.Contains(PermissionGroup.Administrator) && _defaultPermissions.TryGetValue(PermissionGroup.Administrator, out newPermissions)) { AddPermissions(newPermissions); } // Add the user permissions from the database. if (userRepo != null && guildId.HasValue) { AddPermissions(await userRepo.GetAllAsync(guildId.Value, userId)); } // Add the role permissions from the database. if (roleRepo != null && guildId.HasValue) { foreach (var role in userRoles.OrderBy(r => r.Id)) { AddPermissions(await roleRepo.GetAllAsync(guildId.Value, role.Id)); } } // Add the default permissions. if (userPermissions.Contains(PermissionGroup.Moderator) && _defaultPermissions.TryGetValue(PermissionGroup.Moderator, out newPermissions)) { AddPermissions(newPermissions); } // Add the everyone role if (roleRepo != null && guildId.HasValue) { AddPermissions(await roleRepo.GetAllAsync(guildId.Value, guildId.Value)); } if (_defaultPermissions.TryGetValue(PermissionGroup.User, out newPermissions)) { AddPermissions(newPermissions); } // Store into the cache. var allowedPermissions = permissions.Where(kv => kv.Value).Select(kv => kv.Key).ToArray(); _logger.LogDebug("Loaded the permissions for {Username} in {Duration:0.00} ms.", user.Username, stopwatch.Elapsed.TotalMilliseconds); await _cache.SetAsync(cacheKey, allowedPermissions, CacheTime); return(allowedPermissions); }
protected override async Task <JobResult> ProcessQueueEntryAsync(QueueEntryContext <EventNotificationWorkItem> context) { var eventModel = await _eventRepository.GetByIdAsync(context.QueueEntry.Value.EventId).AnyContext(); if (eventModel == null) { return(JobResult.FailedWithMessage($"Could not load event: {context.QueueEntry.Value.EventId}")); } var eventNotification = new EventNotification(context.QueueEntry.Value, eventModel); bool shouldLog = eventNotification.Event.ProjectId != Settings.Current.InternalProjectId; int emailsSent = 0; _logger.Trace().Message(() => $"Process notification: project={eventNotification.Event.ProjectId} event={eventNotification.Event.Id} stack={eventNotification.Event.StackId}").WriteIf(shouldLog); var project = await _projectRepository.GetByIdAsync(eventNotification.Event.ProjectId, true).AnyContext(); if (project == null) { return(JobResult.FailedWithMessage($"Could not load project: {eventNotification.Event.ProjectId}.")); } _logger.Trace().Message(() => $"Loaded project: name={project.Name}").WriteIf(shouldLog); var organization = await _organizationRepository.GetByIdAsync(project.OrganizationId, true).AnyContext(); if (organization == null) { return(JobResult.FailedWithMessage($"Could not load organization: {project.OrganizationId}")); } _logger.Trace().Message(() => $"Loaded organization: {organization.Name}").WriteIf(shouldLog); var stack = await _stackRepository.GetByIdAsync(eventNotification.Event.StackId).AnyContext(); if (stack == null) { return(JobResult.FailedWithMessage($"Could not load stack: {eventNotification.Event.StackId}")); } if (!organization.HasPremiumFeatures) { _logger.Info().Message("Skipping \"{0}\" because organization \"{1}\" does not have premium features.", eventNotification.Event.Id, eventNotification.Event.OrganizationId).WriteIf(shouldLog); return(JobResult.Success); } if (stack.DisableNotifications || stack.IsHidden) { _logger.Info().Message("Skipping \"{0}\" because stack \"{1}\" notifications are disabled or stack is hidden.", eventNotification.Event.Id, eventNotification.Event.StackId).WriteIf(shouldLog); return(JobResult.Success); } if (context.CancellationToken.IsCancellationRequested) { return(JobResult.Cancelled); } _logger.Trace().Message(() => $"Loaded stack: title={stack.Title}").WriteIf(shouldLog); int totalOccurrences = stack.TotalOccurrences; // after the first 2 occurrences, don't send a notification for the same stack more then once every 30 minutes var lastTimeSentUtc = await _cacheClient.GetAsync <DateTime>(String.Concat("notify:stack-throttle:", eventNotification.Event.StackId), DateTime.MinValue).AnyContext(); if (totalOccurrences > 2 && !eventNotification.IsRegression && lastTimeSentUtc != DateTime.MinValue && lastTimeSentUtc > DateTime.UtcNow.AddMinutes(-30)) { _logger.Info().Message("Skipping message because of stack throttling: last sent={0} occurrences={1}", lastTimeSentUtc, totalOccurrences).WriteIf(shouldLog); return(JobResult.Success); } // don't send more than 10 notifications for a given project every 30 minutes var projectTimeWindow = TimeSpan.FromMinutes(30); string cacheKey = String.Concat("notify:project-throttle:", eventNotification.Event.ProjectId, "-", DateTime.UtcNow.Floor(projectTimeWindow).Ticks); double notificationCount = await _cacheClient.IncrementAsync(cacheKey, 1, projectTimeWindow).AnyContext(); if (notificationCount > 10 && !eventNotification.IsRegression) { _logger.Info().Project(eventNotification.Event.ProjectId).Message("Skipping message because of project throttling: count={0}", notificationCount).WriteIf(shouldLog); return(JobResult.Success); } if (context.CancellationToken.IsCancellationRequested) { return(JobResult.Cancelled); } foreach (var kv in project.NotificationSettings) { var settings = kv.Value; _logger.Trace().Message(() => $"Processing notification: user={kv.Key}").WriteIf(shouldLog); var user = await _userRepository.GetByIdAsync(kv.Key).AnyContext(); if (String.IsNullOrEmpty(user?.EmailAddress)) { _logger.Error("Could not load user {0} or blank email address {1}.", kv.Key, user?.EmailAddress ?? ""); continue; } if (!user.IsEmailAddressVerified) { _logger.Info().Message("User {0} with email address {1} has not been verified.", user.Id, user.EmailAddress).WriteIf(shouldLog); continue; } if (!user.EmailNotificationsEnabled) { _logger.Info().Message("User {0} with email address {1} has email notifications disabled.", user.Id, user.EmailAddress).WriteIf(shouldLog); continue; } if (!user.OrganizationIds.Contains(project.OrganizationId)) { _logger.Error().Message("Unauthorized user: project={0} user={1} organization={2} event={3}", project.Id, kv.Key, project.OrganizationId, eventNotification.Event.Id).Write(); continue; } _logger.Trace().Message(() => $"Loaded user: email={user.EmailAddress}").WriteIf(shouldLog); bool shouldReportNewError = settings.ReportNewErrors && eventNotification.IsNew && eventNotification.Event.IsError(); bool shouldReportCriticalError = settings.ReportCriticalErrors && eventNotification.IsCritical && eventNotification.Event.IsError(); bool shouldReportRegression = settings.ReportEventRegressions && eventNotification.IsRegression; bool shouldReportNewEvent = settings.ReportNewEvents && eventNotification.IsNew; bool shouldReportCriticalEvent = settings.ReportCriticalEvents && eventNotification.IsCritical; bool shouldReport = shouldReportNewError || shouldReportCriticalError || shouldReportRegression || shouldReportNewEvent || shouldReportCriticalEvent; _logger.Trace().Message(() => $"Settings: newerror={settings.ReportNewErrors} criticalerror={settings.ReportCriticalErrors} regression={settings.ReportEventRegressions} new={settings.ReportNewEvents} critical={settings.ReportCriticalEvents}").WriteIf(shouldLog); _logger.Trace().Message(() => $"Should process: newerror={shouldReportNewError} criticalerror={shouldReportCriticalError} regression={shouldReportRegression} new={shouldReportNewEvent} critical={shouldReportCriticalEvent}").WriteIf(shouldLog); var request = eventNotification.Event.GetRequestInfo(); // check for known bots if the user has elected to not report them if (shouldReport && !String.IsNullOrEmpty(request?.UserAgent)) { var botPatterns = project.Configuration.Settings.ContainsKey(SettingsDictionary.KnownKeys.UserAgentBotPatterns) ? project.Configuration.Settings.GetStringCollection(SettingsDictionary.KnownKeys.UserAgentBotPatterns).ToList() : new List <string>(); var info = await _parser.ParseAsync(request.UserAgent, eventNotification.Event.ProjectId).AnyContext(); if (info != null && info.Device.IsSpider || request.UserAgent.AnyWildcardMatches(botPatterns)) { shouldReport = false; _logger.Info().Message("Skipping because event is from a bot \"{0}\".", request.UserAgent).WriteIf(shouldLog); } } if (!shouldReport) { continue; } var model = new EventNotificationModel(eventNotification) { ProjectName = project.Name, TotalOccurrences = totalOccurrences }; // don't send notifications in non-production mode to email addresses that are not on the outbound email list. if (Settings.Current.WebsiteMode != WebsiteMode.Production && !Settings.Current.AllowedOutboundAddresses.Contains(v => user.EmailAddress.ToLowerInvariant().Contains(v))) { _logger.Info().Message("Skipping because email is not on the outbound list and not in production mode.").WriteIf(shouldLog); continue; } _logger.Trace("Sending email to {0}...", user.EmailAddress); await _mailer.SendEventNoticeAsync(user.EmailAddress, model).AnyContext(); emailsSent++; _logger.Trace().Message(() => "Done sending email.").WriteIf(shouldLog); } // if we sent any emails, mark the last time a notification for this stack was sent. if (emailsSent > 0) { await _cacheClient.SetAsync(String.Concat("notify:stack-throttle:", eventNotification.Event.StackId), DateTime.UtcNow, DateTime.UtcNow.AddMinutes(15)).AnyContext(); _logger.Info().Message("Notifications sent: event={0} stack={1} count={2}", eventNotification.Event.Id, eventNotification.Event.StackId, emailsSent).WriteIf(shouldLog); } return(JobResult.Success); }
public override async Task EventBatchProcessingAsync(ICollection <EventContext> contexts) { if (_options.AppMode == AppMode.Development) { return; } var firstContext = contexts.First(); if (!firstContext.Project.DeleteBotDataEnabled || !firstContext.IncludePrivateInformation) { return; } // Throttle errors by client ip address to no more than X every 5 minutes. var clientIpAddressGroups = contexts.GroupBy(c => c.Event.GetRequestInfo()?.ClientIpAddress); foreach (var clientIpAddressGroup in clientIpAddressGroups) { if (String.IsNullOrEmpty(clientIpAddressGroup.Key) || clientIpAddressGroup.Key.IsPrivateNetwork()) { continue; } var clientIpContexts = clientIpAddressGroup.ToList(); string throttleCacheKey = String.Concat("bot:", clientIpAddressGroup.Key, ":", SystemClock.UtcNow.Floor(_throttlingPeriod).Ticks); int? requestCount = await _cache.GetAsync <int?>(throttleCacheKey, null).AnyContext(); if (requestCount.HasValue) { await _cache.IncrementAsync(throttleCacheKey, clientIpContexts.Count).AnyContext(); requestCount += clientIpContexts.Count; } else { await _cache.SetAsync(throttleCacheKey, clientIpContexts.Count, SystemClock.UtcNow.Ceiling(_throttlingPeriod)).AnyContext(); requestCount = clientIpContexts.Count; } if (requestCount < _options.BotThrottleLimit) { continue; } _logger.LogInformation("Bot throttle triggered. IP: {IP} Time: {ThrottlingPeriod} Project: {project}", clientIpAddressGroup.Key, SystemClock.UtcNow.Floor(_throttlingPeriod), firstContext.Event.ProjectId); // The throttle was triggered, go and delete all the errors that triggered the throttle to reduce bot noise in the system await _workItemQueue.EnqueueAsync(new RemoveBotEventsWorkItem { OrganizationId = firstContext.Event.OrganizationId, ProjectId = firstContext.Event.ProjectId, ClientIpAddress = clientIpAddressGroup.Key, UtcStartDate = SystemClock.UtcNow.Floor(_throttlingPeriod), UtcEndDate = SystemClock.UtcNow.Ceiling(_throttlingPeriod) }).AnyContext(); clientIpContexts.ForEach(c => { c.IsDiscarded = true; c.IsCancelled = true; }); } }
public Task <IEnumerable <Scope> > GetAsync(string key) { return(cacheClient.GetAsync <IEnumerable <Scope> >(key)); }
private async Task <bool> ShouldRefreshGlobalViewAsync() { return((await cache.GetAsync <int>(GetCacheKey())) == 1); }
/// <summary> /// Cache get. /// </summary> private void GetAsync(BenchmarkState state) { var idx = BenchmarkUtils.GetRandomInt(Dataset); _cache.GetAsync(idx).Wait(); }
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 if (_logger.IsEnabled(LogLevel.Trace)) { _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(); } } } }
public override async Task EventBatchProcessingAsync(ICollection <EventContext> contexts) { var identityGroups = contexts.Where(c => String.IsNullOrEmpty(c.Event.SessionId) && c.Event.GetUserIdentity()?.Identity != null) .OrderBy(c => c.Event.Date) .GroupBy(c => c.Event.GetUserIdentity().Identity); foreach (var identityGroup in identityGroups) { string cacheKey = $"{identityGroup.First().Project.Id}:identity:{identityGroup.Key.ToSHA1()}"; string sessionId = null; EventContext sessionStartContext = null; var sessionsToUpdate = new Dictionary <string, EventContext>(); foreach (var context in identityGroup) { if (!context.Event.IsSessionStart() && String.IsNullOrEmpty(sessionId)) { sessionId = await _cacheClient.GetAsync <string>(cacheKey, null).AnyContext(); if (!String.IsNullOrEmpty(sessionId)) { await _cacheClient.SetExpirationAsync(cacheKey, _sessionTimeout).AnyContext(); await _cacheClient.SetExpirationAsync(GetSessionStartEventIdCacheKey(context.Project.Id, sessionId), _sessionTimeout).AnyContext(); } } if (context.Event.IsSessionStart() || String.IsNullOrEmpty(sessionId)) { if (context.Event.IsSessionStart() && !String.IsNullOrEmpty(sessionId)) { await CreateSessionEndEventAsync(context, sessionId).AnyContext(); if (sessionStartContext != null) { sessionStartContext.Event.UpdateSessionStart(context.Event.Date.UtcDateTime, isSessionEnd: true); } else { await UpdateSessionStartEventAsync(context, sessionId, isSessionEnd : true); } } sessionId = context.Event.SessionId = ObjectId.GenerateNewId(context.Event.Date.DateTime).ToString(); await _cacheClient.SetAsync(cacheKey, sessionId, _sessionTimeout).AnyContext(); if (!context.Event.IsSessionStart()) { var lastContext = GetLastActivity(identityGroup.Where(c => c.Event.Date.Ticks > context.Event.Date.Ticks).ToList()); bool isSessionEnd = lastContext != null && (lastContext.Event.IsSessionStart() || lastContext.Event.IsSessionEnd()); sessionStartContext = await CreateSessionStartEventAsync(context, lastContext?.Event.Date.UtcDateTime, isSessionEnd).AnyContext(); if (lastContext == null || !isSessionEnd) { await _cacheClient.SetAsync(GetSessionStartEventIdCacheKey(context.Project.Id, sessionId), sessionStartContext.Event.Id, _sessionTimeout).AnyContext(); } } } else { context.Event.SessionId = sessionId; if (sessionStartContext == null) { sessionsToUpdate[sessionId] = context; } } if (context.Event.IsSessionStart()) { sessionStartContext = context; } else if (context.Event.IsSessionEnd()) { await _cacheClient.RemoveAllAsync(new [] { cacheKey, GetSessionStartEventIdCacheKey(context.Project.Id, sessionId) }).AnyContext(); sessionId = null; } } foreach (var pair in sessionsToUpdate) { await UpdateSessionStartEventAsync(pair.Value, pair.Key, pair.Value.Event.IsSessionEnd()); } } }
public async Task <bool> OnHandle(MessageContext context, CLoginReqMessage message) { var session = context.GetSession <Session>(); var logger = _logger.ForContext( ("RemoteEndPoint", session.RemoteEndPoint.ToString()), ("Message", message.ToJson())); logger.Debug("Login"); var allowedVersions = _appOptions.CurrentValue.ClientVersions; if (allowedVersions.All(x => message.Version != x)) { logger.Information("Invalid client version={Version} supported versions are {SupportedVersions}", message.Version.ToString(), string.Join(",", allowedVersions.Select(x => x.ToString()))); session.Send(new SLoginAckMessage(GameLoginResult.WrongVersion)); await session.CloseAsync(); return(true); } if (_sessionManager.Sessions.Count >= _networkOptions.MaxSessions) { session.Send(new SLoginAckMessage(GameLoginResult.ServerFull)); return(true); } // Validate session var sessionId = await _cacheClient.GetAsync <string>(Constants.Cache.SessionKey(message.AccountId)); if (!sessionId.HasValue || !sessionId.Value.Equals(message.SessionId)) { logger.Information("Invalid session id"); session.Send(new SLoginAckMessage(GameLoginResult.SessionTimeout)); return(true); } AccountEntity accountEntity; using (var db = _databaseService.Open <AuthContext>()) { var accountId = (long)message.AccountId; accountEntity = await db.Accounts .Include(x => x.Bans) .FirstOrDefaultAsync(x => x.Id == accountId); } if (accountEntity == null) { logger.Information("Wrong login"); session.Send(new SLoginAckMessage(GameLoginResult.SessionTimeout)); return(true); } // Check ban status var now = DateTimeOffset.Now.ToUnixTimeSeconds(); var ban = accountEntity.Bans.FirstOrDefault(x => x.Duration == null || x.Date + x.Duration > now); if (ban != null) { var unbanDate = DateTimeOffset.MinValue; if (ban.Duration != null) { unbanDate = DateTimeOffset.FromUnixTimeSeconds(ban.Date + (ban.Duration ?? 0)); } logger.Information("Account is banned until {UnbanDate}", unbanDate); session.Send(new SLoginAckMessage(GameLoginResult.SessionTimeout)); return(true); } var account = new Account((ulong)accountEntity.Id, accountEntity.Username, accountEntity.Nickname, (SecurityLevel)accountEntity.SecurityLevel); if (message.KickConnection) { var oldPlr = _playerManager[account.Id]; if (oldPlr != null) { logger.Information("Kicking old connection hostId={HostId}", oldPlr.Session.HostId); await oldPlr.DisconnectAsync(); } } if (_playerManager.Contains(account.Id)) { // TODO Check if logged in on another server logger.Information("Account is already logged in"); session.Send(new SLoginAckMessage(GameLoginResult.TerminateOtherConnection)); return(true); } using (var db = _databaseService.Open <GameContext>()) { var plr = await db.Players .Include(x => x.Characters) .Include(x => x.Items) .Include(x => x.Licenses) .FirstOrDefaultAsync(x => x.Id == accountEntity.Id); if (plr == null) { var levelInfo = _gameDataService.Levels.GetValueOrDefault(_gameOptions.StartLevel); if (levelInfo == null) { logger.Warning("Invalid StartLevel={StartLevel} in config", _gameOptions.StartLevel); } plr = new PlayerEntity { Id = (int)account.Id, AP = _gameOptions.StartAP, PEN = _gameOptions.StartPEN, Coins1 = _gameOptions.StartCoins1, Coins2 = _gameOptions.StartCoins2, TotalExperience = (int)(levelInfo?.TotalExperience ?? 0) }; db.Players.Add(plr); await db.SaveChangesAsync(); } session.Player = _serviceProvider.GetRequiredService <Player>(); session.Player.Initialize(session, account, plr); session.SessionId = message.SessionId; } _playerManager.Add(session.Player); logger.Information("Login success"); var result = string.IsNullOrWhiteSpace(account.Nickname) ? GameLoginResult.ChooseNickname : GameLoginResult.OK; session.Send(new SLoginAckMessage(result, account.Id)); if (!string.IsNullOrWhiteSpace(account.Nickname)) { await session.Player.SendAccountInformation(); } return(true); }
public async Task <bool> IsLockedAsync(string name) { var result = await Run.WithRetriesAsync(() => _cacheClient.GetAsync <object>(name), logger : _logger).AnyContext(); return(result.HasValue); }
public override async Task EventProcessingAsync(EventContext context) { var user = context.Event.GetUserIdentity(); if (String.IsNullOrEmpty(user?.Identity) || !String.IsNullOrEmpty(context.Event.SessionId)) { return; } string cacheKey = $"session:{context.Event.ProjectId}:{user.Identity}"; var sessionId = context.Event.Type != Event.KnownTypes.SessionStart ? await _cacheClient.GetAsync <string>(cacheKey, null).AnyContext() : null; if (sessionId == null) { sessionId = Guid.NewGuid().ToString("N"); await _cacheClient.SetAsync(cacheKey, sessionId, _sessionTimeout).AnyContext(); } else { await _cacheClient.SetExpirationAsync(cacheKey, _sessionTimeout).AnyContext(); } context.Event.SessionId = sessionId; if (context.Event.Type == Event.KnownTypes.SessionEnd) { await _cacheClient.RemoveAsync(cacheKey).AnyContext(); } }
public static async Task <BlackjackManager> FromCacheClientAsync(ICacheClient client, ulong channelId, ulong userId) { return(FromContext( await client.GetAsync <BlackjackContext>($"miki:blackjack:{channelId}:{userId}") )); }
public override async Task EventBatchProcessingAsync(ICollection <EventContext> contexts) { var sessionGroups = contexts.Where(c => !String.IsNullOrEmpty(c.Event.SessionId)) .OrderBy(c => c.Event.Date) .GroupBy(c => c.Event.SessionId); foreach (var sessionGroup in sessionGroups) { var oldestContext = sessionGroup.First(); string cacheKey = $"{oldestContext.Project.Id}:start:{oldestContext.Event.SessionId}"; string sessionStartEventId = await _cacheClient.GetAsync <string>(cacheKey, null).AnyContext(); if (!String.IsNullOrEmpty(sessionStartEventId)) { await _cacheClient.SetExpirationAsync(cacheKey, _sessionTimeout).AnyContext(); } // Deduplicate session start and end events. sessionGroup.Where(c => c.Event.IsSessionStart()).Skip(String.IsNullOrEmpty(sessionStartEventId) ? 1 : 0).ForEach(c => c.IsCancelled = true); sessionGroup.OrderByDescending(c => c.Event.Date).Where(c => c.Event.IsSessionEnd()).Skip(1).ForEach(c => c.IsCancelled = true); var validContexts = sessionGroup.Where(c => !c.IsCancelled).ToList(); if (validContexts.Count == 0) { continue; } oldestContext = validContexts.First(); var newestContext = validContexts.Last(); var sessionStartEventContext = validContexts.FirstOrDefault(c => c.Event.IsSessionStart()); UpdateEventContextDate(sessionStartEventContext, oldestContext.Event.Date); var sessionEndEventContext = validContexts.FirstOrDefault(c => c.Event.IsSessionEnd()); UpdateEventContextDate(sessionEndEventContext, newestContext.Event.Date); // Update or create the session start event. var createSessionStartEvent = String.IsNullOrEmpty(sessionStartEventId) && sessionStartEventContext == null; if (createSessionStartEvent) { string sessionStartId = await CreateSessionStartEventAsync(oldestContext, newestContext.Event.Date.UtcDateTime, sessionEndEventContext != null).AnyContext(); if (sessionEndEventContext == null) { await _cacheClient.SetAsync(cacheKey, sessionStartId, _sessionTimeout).AnyContext(); } } else if (sessionStartEventContext != null) { if (validContexts.Count > 1) { sessionStartEventContext.Event.UpdateSessionStart(newestContext.Event.Date.UtcDateTime, sessionEndEventContext != null); } if (sessionEndEventContext == null) { sessionStartEventContext.SetProperty(CREATE_SESSION_START_CACHE_ENTRY, true); } } else { bool closeSession = sessionEndEventContext != null; await _eventRepository.UpdateSessionStartLastActivityAsync(sessionStartEventId, newestContext.Event.Date.UtcDateTime, closeSession).AnyContext(); if (closeSession) { await _cacheClient.RemoveAsync(cacheKey).AnyContext(); } } } }
public async Task CanIncrementUsageAsync() { var messageBus = GetService <IMessageBus>(); var countdown = new AsyncCountdownEvent(2); await messageBus.SubscribeAsync <PlanOverage>(po => { _logger.Info($"Plan Overage for {po.OrganizationId} (Hourly: {po.IsHourly})"); countdown.Signal(); }); var o = await _organizationRepository.AddAsync(new Organization { Name = "Test", MaxEventsPerMonth = 750, PlanId = BillingManager.SmallPlan.Id }); var project = await _projectRepository.AddAsync(new Project { Name = "Test", OrganizationId = o.Id, NextSummaryEndOfDayTicks = SystemClock.UtcNow.Ticks }, opt => opt.Cache()); await _configuration.Client.RefreshAsync(Indices.All); Assert.InRange(o.GetHourlyEventLimit(), 1, 750); int totalToIncrement = o.GetHourlyEventLimit() - 1; Assert.False(await _usageService.IncrementUsageAsync(o.Id, project.Id, false, totalToIncrement)); await _configuration.Client.RefreshAsync(Indices.All); o = await _organizationRepository.GetByIdAsync(o.Id); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(2, countdown.CurrentCount); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id, project.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id, project.Id), 0)); Assert.True(await _usageService.IncrementUsageAsync(o.Id, project.Id, false, 2)); await _configuration.Client.RefreshAsync(Indices.All); o = await _organizationRepository.GetByIdAsync(o.Id); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(1, countdown.CurrentCount); Assert.Equal(totalToIncrement + 2, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement + 2, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(totalToIncrement + 2, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement + 2, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(1, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(1, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id, project.Id), 0)); Assert.Equal(1, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); Assert.Equal(1, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id, project.Id), 0)); o = await _organizationRepository.AddAsync(new Organization { Name = "Test", MaxEventsPerMonth = 750, PlanId = BillingManager.SmallPlan.Id }); project = await _projectRepository.AddAsync(new Project { Name = "Test", OrganizationId = o.Id, NextSummaryEndOfDayTicks = SystemClock.UtcNow.Ticks }, opt => opt.Cache()); await _configuration.Client.RefreshAsync(Indices.All); await _cache.RemoveAllAsync(); totalToIncrement = o.GetHourlyEventLimit() + 20; Assert.True(await _usageService.IncrementUsageAsync(o.Id, project.Id, false, totalToIncrement)); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(0, countdown.CurrentCount); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(20, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(20, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id, project.Id), 0)); Assert.Equal(20, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); Assert.Equal(20, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id, project.Id), 0)); }
public override Task <object> GetOrDefaultAsync(string key) { return(_cacheClient.GetAsync <object>(GetLocalizedKey(key))); }
public static async Task<bool> IsOverRequestLimitAsync(string organizationId, ICacheClient cacheClient, int apiThrottleLimit) { var cacheKey = String.Concat("api", ":", organizationId, ":", DateTime.UtcNow.Floor(TimeSpan.FromMinutes(15)).Ticks); var limit = await cacheClient.GetAsync<long>(cacheKey).AnyContext(); return limit.HasValue && limit.Value >= apiThrottleLimit; }
public async Task BuildAsync <T>(QueryBuilderContext <T> ctx) where T : class, new() { if (!ctx.Source.ShouldEnforceEventStackFilter()) { return; } // TODO: Handle search expressions as well string filter = ctx.Source.GetFilterExpression() ?? String.Empty; bool altInvertRequested = false; if (filter.StartsWith("@!")) { altInvertRequested = true; filter = filter.Substring(2); ctx.Source.FilterExpression(filter); } // when inverting to get excluded stack ids, add is_deleted as an alternate inverted criteria if (ctx.Options.GetSoftDeleteMode() == SoftDeleteQueryMode.ActiveOnly) { ctx.SetAlternateInvertedCriteria(new TermNode { Field = "is_deleted", Term = "true" }); } var stackFilter = await _eventStackFilter.GetStackFilterAsync(filter, ctx); const int stackIdLimit = 10000; string[] stackIds = Array.Empty <string>(); long stackTotal = 0; string stackFilterValue = stackFilter.Filter; bool isStackIdsNegated = false; //= stackFilter.HasStatusOpen && !altInvertRequested; if (isStackIdsNegated) { stackFilterValue = stackFilter.InvertedFilter; } if (String.IsNullOrEmpty(stackFilterValue) && (!ctx.Source.ShouldEnforceEventStackFilter() || ctx.Options.GetSoftDeleteMode() != SoftDeleteQueryMode.ActiveOnly)) { return; } _logger.LogTrace("Source: {Filter} Stack Filter: {StackFilter} Inverted Stack Filter: {InvertedStackFilter}", filter, stackFilter.Filter, stackFilter.InvertedFilter); var systemFilterQuery = GetSystemFilterQuery(ctx, isStackIdsNegated); systemFilterQuery.FilterExpression(stackFilterValue); var softDeleteMode = isStackIdsNegated ? SoftDeleteQueryMode.All : SoftDeleteQueryMode.ActiveOnly; systemFilterQuery.EventStackFilterInverted(isStackIdsNegated); FindResults <Stack> results = null; var tooManyStacksCheck = await _cacheClient.GetAsync <long>(GetQueryHash(systemFilterQuery)); if (tooManyStacksCheck.HasValue) { stackTotal = tooManyStacksCheck.Value; } else { results = await _stackRepository.GetIdsByQueryAsync(q => systemFilterQuery.As <Stack>(), o => o.PageLimit(stackIdLimit).SoftDeleteMode(softDeleteMode)).AnyContext(); stackTotal = results.Total; } if (stackTotal > stackIdLimit) { if (!tooManyStacksCheck.HasValue) { await _cacheClient.SetAsync(GetQueryHash(systemFilterQuery), stackTotal, TimeSpan.FromMinutes(15)); } _logger.LogTrace("Query: {query} will be inverted due to id limit: {ResultCount}", stackFilterValue, stackTotal); isStackIdsNegated = !isStackIdsNegated; stackFilterValue = isStackIdsNegated ? stackFilter.InvertedFilter : stackFilter.Filter; systemFilterQuery.FilterExpression(stackFilterValue); softDeleteMode = isStackIdsNegated ? SoftDeleteQueryMode.All : SoftDeleteQueryMode.ActiveOnly; systemFilterQuery.EventStackFilterInverted(isStackIdsNegated); tooManyStacksCheck = await _cacheClient.GetAsync <long>(GetQueryHash(systemFilterQuery)); if (tooManyStacksCheck.HasValue) { stackTotal = tooManyStacksCheck.Value; } else { results = await _stackRepository.GetIdsByQueryAsync(q => systemFilterQuery.As <Stack>(), o => o.PageLimit(stackIdLimit).SoftDeleteMode(softDeleteMode)).AnyContext(); stackTotal = results.Total; } } if (stackTotal > stackIdLimit) { if (!tooManyStacksCheck.HasValue) { await _cacheClient.SetAsync(GetQueryHash(systemFilterQuery), stackTotal, TimeSpan.FromMinutes(15)); } throw new DocumentLimitExceededException("Please limit your search criteria."); } if (results?.Hits != null) { stackIds = results.Hits.Select(h => h.Id).ToArray(); } _logger.LogTrace("Setting stack filter with {IdCount} ids", stackIds?.Length ?? 0); if (!isStackIdsNegated) { if (stackIds.Length > 0) { ctx.Source.Stack(stackIds); } else { ctx.Source.Stack("none"); } } else { if (stackIds.Length > 0) { ctx.Source.ExcludeStack(stackIds); } } // Strips stack only fields and stack only special fields string eventFilter = await _eventStackFilter.GetEventFilterAsync(filter, ctx); ctx.Source.FilterExpression(eventFilter); }