/** * @see io.apiman.gateway.engine.components.IRateLimiterComponent#accept(java.lang.String, * io.apiman.gateway.engine.rates.RateBucketPeriod, int, * io.apiman.gateway.engine.async.IAsyncResultHandler) */ @Override public void accept( String bucketId, RateBucketPeriod period, int limit, IAsyncResultHandler<RateLimitResponse> handler) { RateLimiterBucket bucket = null; synchronized (mutex) { bucket = (RateLimiterBucket) getCache().get(bucketId); if (bucket == null) { bucket = new RateLimiterBucket(); getCache().put(bucketId, bucket); } bucket.resetIfNecessary(period); RateLimitResponse response = new RateLimitResponse(); if (bucket.getCount() >= limit) { response.setAccepted(false); } else { bucket.setCount(bucket.getCount() + 1); bucket.setLast(System.currentTimeMillis()); response.setAccepted(true); } int reset = (int) (bucket.getResetMillis(period) / 1000L); response.setReset(reset); response.setRemaining(limit - bucket.getCount()); handler.handle(AsyncResultImpl.<RateLimitResponse>create(response)); getCache().put(bucketId, bucket); } }
/** * Update the bucket in ES and then return the rate limit response to the original handler. If the * update fails because we have a stale version, then try the whole thing again (because we * conflicted with another request). * * @param id * @param bucket * @param rlr * @param version * @param limit * @param period * @param bucketId * @param increment * @param handler */ protected void updateBucketAndReturn( final String id, final RateLimiterBucket bucket, final RateLimitResponse rlr, final long version, final String bucketId, final RateBucketPeriod period, final long limit, final long increment, final IAsyncResultHandler<RateLimitResponse> handler) { Index index = new Index.Builder(bucket) .refresh(false) .index(getIndexName()) .setParameter(Parameters.OP_TYPE, "index") // $NON-NLS-1$ .setParameter(Parameters.VERSION, String.valueOf(version)) .type("rateBucket") .id(id) .build(); //$NON-NLS-1$ try { getClient().execute(index); handler.handle(AsyncResultImpl.create(rlr)); } catch (Throwable e) { // FIXME need to fix this now that we've switched to jest! // if (ESUtils.rootCause(e) instanceof VersionConflictEngineException) { // // If we got a version conflict, then it means some other request // // managed to update the ES document since we retrieved it. Therefore // // everything we've done is out of date, so we should do it all // // over again. // accept(bucketId, period, limit, increment, handler); // } else { handler.handle(AsyncResultImpl.<RateLimitResponse>create(e)); // } } }
/** * @see io.apiman.gateway.engine.components.IRateLimiterComponent#accept(java.lang.String, * io.apiman.gateway.engine.rates.RateBucketPeriod, long, long, * io.apiman.gateway.engine.async.IAsyncResultHandler) */ @Override public void accept( final String bucketId, final RateBucketPeriod period, final long limit, final long increment, final IAsyncResultHandler<RateLimitResponse> handler) { final String id = id(bucketId); try { Get get = new Get.Builder(getIndexName(), id).type("rateBucket").build(); // $NON-NLS-1$ JestResult result = getClient().execute(get); RateLimiterBucket bucket; long version; if (result.isSucceeded()) { // use the existing bucket version = result.getJsonObject().get("_version").getAsLong(); // $NON-NLS-1$ bucket = result.getSourceAsObject(RateLimiterBucket.class); } else { // make a new bucket version = 0; bucket = new RateLimiterBucket(); } bucket.resetIfNecessary(period); final RateLimitResponse rlr = new RateLimitResponse(); if (bucket.getCount() > limit) { rlr.setAccepted(false); } else { rlr.setAccepted(bucket.getCount() < limit); bucket.setCount(bucket.getCount() + increment); bucket.setLast(System.currentTimeMillis()); } int reset = (int) (bucket.getResetMillis(period) / 1000L); rlr.setReset(reset); rlr.setRemaining(limit - bucket.getCount()); updateBucketAndReturn(id, bucket, rlr, version, bucketId, period, limit, increment, handler); } catch (Throwable e) { handler.handle(AsyncResultImpl.create(e, RateLimitResponse.class)); } }
@Override public void end() { responseHandler.handle(AsyncResultImpl.<IApiConnectionResponse>create(this)); }