public override void Process(ErrorPipelineContext ctx) { if (Settings.Current.WebsiteMode == WebsiteMode.Dev) { return; } // Throttle errors by client ip address to no more than X every 5 minutes. string clientIp = null; if (ctx.Error.RequestInfo != null && !String.IsNullOrEmpty(ctx.Error.RequestInfo.ClientIpAddress)) { clientIp = ctx.Error.RequestInfo.ClientIpAddress; } if (String.IsNullOrEmpty(clientIp)) { return; } string throttleCacheKey = String.Concat("bot:", clientIp, ":", DateTime.Now.Floor(_throttlingPeriod).Ticks); var requestCount = _cacheClient.Get <int?>(throttleCacheKey); if (requestCount != null) { _cacheClient.Increment(throttleCacheKey, 1); requestCount++; } else { _cacheClient.Set(throttleCacheKey, 1, _throttlingPeriod); requestCount = 1; } if (requestCount < Settings.Current.BotThrottleLimit) { return; } Log.Info().Message("Bot throttle triggered. IP: {0} Time: {1} Project: {2}", clientIp, DateTime.Now.Floor(_throttlingPeriod), ctx.Error.ProjectId).Project(ctx.Error.ProjectId).Write(); // the throttle was triggered, go and delete all the errors that triggered the throttle to reduce bot noise in the system Task.Run(() => _errorRepository.RemoveAllByClientIpAndDateAsync(clientIp, DateTime.Now.Floor(_throttlingPeriod), DateTime.Now.Ceiling(_throttlingPeriod))); ctx.IsCancelled = true; }