<?php namespace Gatekeeper; use Cache; use Gatekeeper\Alerts\BandwidthLimitApproached; use Gatekeeper\Alerts\BandwidthLimitExceeded; $Endpoint = $_EVENT['request']->getEndpoint(); // check endpoint bandwidth bucket (unlike requests, it can't be dripped until after the request) if ($Endpoint->GlobalBandwidthPeriod && $Endpoint->GlobalBandwidthCount) { $flagKey = "alerts/endpoints/{$Endpoint->ID}/bandwidth-flagged"; $bucket = HitBuckets::fetch("endpoints/{$Endpoint->ID}/bandwidth"); if ($bucket && $bucket['hits'] < 0) { BandwidthLimitExceeded::open($Endpoint, ['request' => ['uri' => $_EVENT['request']->getUrl()], 'endpointId' => $Endpoint->ID, 'bucket' => $bucket]); Cache::store($flagKey, true); return ApiRequestHandler::throwRateError($bucket['seconds'], 'The global bandwidth limit for this endpoint has been exceeded'); } if ($bucket && $Endpoint->AlertNearMaxRequests && $bucket['hits'] < (1 - $Endpoint->AlertNearMaxRequests) * $Endpoint->GlobalBandwidthCount) { BandwidthLimitApproached::open($Endpoint, ['request' => ['uri' => $_EVENT['request']->getUrl()], 'endpointId' => $Endpoint->ID, 'bucket' => $bucket]); Cache::store($flagKey, true); } elseif (Cache::fetch($flagKey)) { Cache::delete($flagKey); // automatically close any open alerts if there is a flag in the cache // TODO: maybe do this in a cron job instead? foreach ([BandwidthLimitExceeded::class, BandwidthLimitApproached::class] as $alertClass) { $OpenAlert = $alertClass::getByWhere(['Class' => $alertClass, 'EndpointID' => $Endpoint->ID, 'Status' => 'open']); if ($OpenAlert) { $OpenAlert->Status = 'closed'; $OpenAlert->save(); } }
<?php namespace Gatekeeper; use Gatekeeper\Metrics\Metrics; $Endpoint = $_EVENT['request']->getEndpoint(); // append metrics $_EVENT['metrics']['endpointResponsesExecuted'] = Metrics::appendCounter("endpoints/{$Endpoint->ID}/responsesExecuted"); $_EVENT['metrics']['endpointBytesExecuted'] = Metrics::appendCounter("endpoints/{$Endpoint->ID}/bytesExecuted", $_EVENT['Transaction']->ResponseBytes); $_EVENT['metrics']['endpointResponseTime'] = Metrics::appendAverage("endpoints/{$Endpoint->ID}/responseTime", $_EVENT['Transaction']->ResponseTime, $_EVENT['metrics']['endpointResponsesExecuted']); // drip bandwidth bucket if ($Endpoint->GlobalBandwidthPeriod && $Endpoint->GlobalBandwidthCount) { HitBuckets::drip("endpoints/{$Endpoint->ID}/bandwidth", function () use($Endpoint) { return ['seconds' => $Endpoint->GlobalBandwidthPeriod, 'count' => $Endpoint->GlobalBandwidthCount]; }, $_EVENT['Transaction']->ResponseBytes); }
<?php namespace Gatekeeper; use Cache; use Gatekeeper\Alerts\RateLimitApproached; use Gatekeeper\Alerts\RateLimitExceeded; $Endpoint = $_EVENT['request']->getEndpoint(); // drip into endpoint requests bucket if ($Endpoint->GlobalRatePeriod && $Endpoint->GlobalRateCount) { $flagKey = "alerts/endpoints/{$Endpoint->ID}/rate-flagged"; $bucket = HitBuckets::drip("endpoints/{$Endpoint->ID}/requests", function () use($Endpoint) { return ['seconds' => $Endpoint->GlobalRatePeriod, 'count' => $Endpoint->GlobalRateCount]; }); if ($bucket['hits'] < 0) { RateLimitExceeded::open($Endpoint, ['request' => ['uri' => $_EVENT['request']->getUrl()], 'endpointId' => $Endpoint->ID, 'bucket' => $bucket]); Cache::store($flagKey, true); return ApiRequestHandler::throwRateError($bucket['seconds'], 'The global rate limit for this endpoint has been exceeded'); } if ($Endpoint->AlertNearMaxRequests && $bucket['hits'] < (1 - $Endpoint->AlertNearMaxRequests) * $Endpoint->GlobalRateCount) { RateLimitApproached::open($Endpoint, ['request' => ['uri' => $_EVENT['request']->getUrl()], 'endpointId' => $Endpoint->ID, 'bucket' => $bucket]); Cache::store($flagKey, true); } elseif (Cache::fetch($flagKey)) { Cache::delete($flagKey); // automatically close any open alerts if there is a flag in the cache // TODO: maybe do this in a cron job instead? foreach ([RateLimitExceeded::class, RateLimitApproached::class] as $alertClass) { $OpenAlert = $alertClass::getByWhere(['Class' => $alertClass, 'EndpointID' => $Endpoint->ID, 'Status' => 'open']); if ($OpenAlert) { $OpenAlert->Status = 'closed'; $OpenAlert->save();