Skip to content
This repository has been archived by the owner on Mar 24, 2021. It is now read-only.

Commit

Permalink
Add striped rate-limiting
Browse files Browse the repository at this point in the history
Slowness for a single data-set should not result in resource-exhaustion
for the other data sets. This is a resilience measure.

Allow up to 100 requests per minute, with bursting to 5 requests per
second.

We are doing this in the application since we have the knowledge about
URLs in here, rather than in Varnish or nginx.

We need to set rate-limiting high for tests, otherwise the tests fail as
the rate-limiting kicks in.
  • Loading branch information
jabley committed Sep 23, 2014
1 parent 0f07512 commit e5f26b8
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 0 deletions.
19 changes: 19 additions & 0 deletions backdrop/read/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from flask import Flask, jsonify, request
from flask_featureflags import FeatureFlag
from flask_limiter import Limiter

from .query import parse_query_from_request
from .validation import validate_request_args
Expand All @@ -25,6 +26,7 @@

app = Flask("backdrop.read.api")

limiter = Limiter(app)
feature_flags = FeatureFlag(app)

# Configuration
Expand Down Expand Up @@ -153,7 +155,16 @@ def log_error_and_respond(data_set, message, status_code):
return jsonify(status='error', message=message), status_code


def data_group_key():
"""Key used for rate-limiting requests to data-types"""
return '{data_group}:{data_type}'.format(
data_group=request.view_args.get('data_group'),
data_type=request.view_args.get('data_type'))


@app.route('/data/<data_group>/<data_type>', methods=['GET', 'OPTIONS'])
@limiter.limit(app.config.get('DATA_SET_RATE_LIMIT', '100/minute;5/second'),
data_group_key)
def data(data_group, data_type):
with statsd.timer('read.route.data.{data_group}.{data_type}'.format(
data_group=data_group,
Expand All @@ -162,7 +173,15 @@ def data(data_group, data_type):
return fetch(data_set_config)


def data_set_key():
"""Key used for rate-limiting requests to data sets"""
return '{data_set_name}'.format(
data_set_name=request.view_args.get('data_set_name'))


@app.route('/<data_set_name>', methods=['GET', 'OPTIONS'])
@limiter.limit(app.config.get('DATA_SET_RATE_LIMIT', '100/minute;5/second'),
data_set_key)
@http_validation.etag
def query(data_set_name):
with statsd.timer('read.route.{data_set_name}'.format(
Expand Down
2 changes: 2 additions & 0 deletions backdrop/read/config/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
MONGO_PORT = 27017
LOG_LEVEL = "ERROR"

DATA_SET_RATE_LIMIT='10000/second'

from development import STAGECRAFT_URL, STAGECRAFT_DATA_SET_QUERY_TOKEN, SIGNON_API_USER_TOKEN
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
argh==0.25
Flask==0.10.1
Flask-FeatureFlags==0.4
Flask-Limiter==0.6.4
gunicorn==19.1.1
invoke
isodate==0.5.0
Expand Down

0 comments on commit e5f26b8

Please sign in to comment.