Skip to content

Instantly share code, notes, and snippets.

Scaling your API with rate limiters

The following are examples of the four types rate limiters discussed in the accompanying blog post. In the examples below I've used pseudocode-like Ruby, so if you're unfamiliar with Ruby you should be able to easily translate this approach to other languages. Complete examples in Ruby are also provided later in this gist.

In most cases you'll want all these examples to be classes, but I've used simple functions here to keep the code samples brief.

Request rate limiter

This uses a basic token bucket algorithm and relies on the fact that Redis scripts execute atomically. No other operations can run between fetching the count and writing the new count.

@pas256
pas256 / disable-branch-protection.sh
Created October 22, 2022 04:39 — forked from tiesmaster/disable-branch-protection.sh
Enable/disable branch protection on GitHub through their API
#!/bin/bash
OAUTH2_TOKEN=<fill in your own OAUTH2 token>
OWNER=tiesmaster
REPO=Coolkit.Converters # retrieve this with: basename $(git config --get remote.origin.url) .git
curl https://api.github.com/repos/${OWNER}/${REPO}/branches/master \
-H "Authorization: token $OAUTH2_TOKEN" \
-H "Accept: application/vnd.github.loki-preview+json" \
@pas256
pas256 / ribalancer.py
Last active September 17, 2018 22:06 — forked from dialtone/ribalancer.py
Balance RI Instances
import boto3
import argparse
from pprint import pprint as pp
from dateutil.tz import tzutc
from datetime import datetime, timedelta
from collections import defaultdict as dd
class IL(object):
"""
@pas256
pas256 / keybase.md
Created March 17, 2015 05:45
keybase.md

Keybase proof

I hereby claim:

  • I am pas256 on github.
  • I am pas256 (https://keybase.io/pas256) on keybase.
  • I have a public key whose fingerprint is 7554 6406 36F3 4B85 38CE 049D 7900 D81F DCAF CA54

To claim this, I am signing this object:

@pas256
pas256 / CLI
Last active August 29, 2015 14:03
cloud-init
[root@ip-10-0-12-67 ~]# mount /dev/xvdg /mnt
[root@ip-10-0-12-67 ~]# cd /mnt
[root@ip-10-0-12-67 mnt]# mount -t proc proc proc/
[root@ip-10-0-12-67 mnt]# mount -t sysfs sys sys/
[root@ip-10-0-12-67 mnt]# mount -o bind /dev dev/
[root@ip-10-0-12-67 mnt]# chroot /mnt
[root@ip-10-0-12-67 /]# cloud-init --debug init
2014-06-28 00:06:39,123 - util.py[DEBUG]: Reading from /proc/cmdline (quiet=False)
2014-06-28 00:06:39,124 - util.py[DEBUG]: Read 27 bytes from /proc/cmdline
2014-06-28 00:06:39,124 - util.py[DEBUG]: Reading from /proc/uptime (quiet=False)
@pas256
pas256 / template.json
Last active March 15, 2019 17:07
CloudFormation template generated by troposphere.
{
"Outputs": {
"InstanceAccess": {
"Description": "Command to use to SSH to instance",
"Value": {
"Fn::Join": [
"",
[
"ssh -i ",
{
Traceback (most recent call last):
File "/Users/pas/ansible/lib/ansible/runner/__init__.py", line 65, in _executor_hook
result_queue.put(multiprocessing_runner._executor(host))
File "/Users/pas/ansible/lib/ansible/runner/__init__.py", line 281, in _executor
self.callbacks.on_unreachable(host, msg)
File "/Users/pas/ansible/lib/ansible/callbacks.py", line 312, in on_unreachable
msg = "fatal: [%s] => %s" % (host, results)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xbf in position 205: ordinal not in range(128)
@pas256
pas256 / gist:5297243
Created April 2, 2013 23:51
Response
garethbowles1
1:55 spoon16, here's the answer from allenxwang:
1:55 You need to use JDBCConfigurationSource together with DynamicConfiguration, where it can poll the configuration source at some interval. Then add DynamicConfiguration to ConfigurationManager:
1:55 DynamicConfiguration dynamicConfig = ... // create config with JDBCConfigurationSource
1:55 (AggregatedConfiguration) config = (AggregatedConfiguration) ConfigurationManager.getConfigInstance();
1:55 config.addConfiguration(dynamicConfig, "Database");
1:55 Then the fast property will get callback once the value is changed in the database.
@pas256
pas256 / gist:5241852
Created March 25, 2013 23:29
Trying to get aminate to work
# aminate -B ami-86e15bef asgard
Traceback (most recent call last):
File "/usr/bin/aminate", line 9, in <module>
load_entry_point('aminator==1.0.0', 'console_scripts', 'aminate')()
File "/usr/lib/python2.6/site-packages/aminator/cli.py", line 51, in run
sys.exit(Aminator(debug=args.debug).aminate())
File "/usr/lib/python2.6/site-packages/aminator/core.py", line 52, in __init__
log_per_package(self.config, 'per_package')
File "/usr/lib/python2.6/site-packages/aminator/config.py", line 161, in log_per_package
dictConfig(per_package_config.toDict())
@pas256
pas256 / cassandra_tokens.yml
Created March 7, 2013 19:45
Cassandra initial tokens for clusters of any size (where any is 1 to 10 nodes)
# Support for up to 10 Cassandra nodes
initial_tokens:
1:
0: 0
2:
0: 0
1: 85070591730234615865843651857942052864
3:
0: 0
1: 56713727820156410577229101238628035242