Skip to content

Instantly share code, notes, and snippets.

@carpodaster
Last active December 25, 2015 04:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save carpodaster/6920157 to your computer and use it in GitHub Desktop.
Save carpodaster/6920157 to your computer and use it in GitHub Desktop.
class ExternalService
include RateLimiter
def self.work_with_users
rate_limit 20, 2.0, User.find_each do |user|
# Do stuff with each user.
# Pause 2 seconds every 20 iterations
end
end
end
class ExternalService
def self.work_with_users
rate_limiter = 0
User.find_each do |user|
# Do stuff with each user
rate_limiter += 1
sleep 0.8 if rate_limiter % 10 == 0
end
end
end
module RateLimiter
extend ActiveSupport::Concern
def rate_limit *args, &block
self.class.rate_limit(*args, &block)
end
module ClassMethods
def rate_limit allowed_iterations, sleep_time, enum
enum.each_with_index do |data, runs|
yield data
sleep sleep_time if (runs+1) % allowed_iterations == 0
end
end
end
end
require 'spec_helper'
describe RateLimiter do
let(:enum) { 1..10 }
subject { klass.new }
describe '.rate_limit' do
it 'accepts two parameters' do
expect(klass.method(:rate_limit).arity).to eql 3
end
it 'yields to a block' do
expect do |var|
klass.rate_limit 1, 0.0, enum, &var
end.to yield_successive_args(*enum.to_a)
end
it 'sleeps every n iterations' do
limit = 3
klass.stub(:sleep)
klass.should_receive(:sleep).exactly(enum.size / limit).times
klass.rate_limit limit, 10.0, enum, &Proc.new{}
end
end
describe '#rate_limit' do
it 'forwards do its singleton version' do
klass.should_receive(:rate_limit).with 10, 1.0, enum
subject.rate_limit 10, 1.0, enum, &Proc.new{}
end
it 'yields to a block' do
expect do |var|
subject.rate_limit 1, 0.0, enum, &var
end.to yield_successive_args(*enum.to_a)
end
end
def klass
@klass ||= Class.new { include RateLimiter }
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment