rate_limited_scheduler 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/rate_limited_scheduler.rb +89 -0
- metadata +49 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'redis'
|
2
|
+
require 'redis-namespace'
|
3
|
+
|
4
|
+
class RateLimitedScheduler
|
5
|
+
class Configuration
|
6
|
+
attr_accessor :default_threshold, :default_interval
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.configure(&block)
|
10
|
+
block.call(@@configuration)
|
11
|
+
end
|
12
|
+
|
13
|
+
@@configuration = Configuration.new
|
14
|
+
|
15
|
+
self.configure do |config|
|
16
|
+
config.default_threshold = 5
|
17
|
+
config.default_interval = 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(bucket, constraint)
|
21
|
+
# default: 5 executions per second
|
22
|
+
constraint[:threshold] ||= @@configuration.default_threshold
|
23
|
+
constraint[:interval] ||= @@configuration.default_interval
|
24
|
+
|
25
|
+
@bucket = bucket
|
26
|
+
@constraint = constraint
|
27
|
+
@redis = Redis::Namespace.new(:ratelimiter, { :redis => Redis.new })
|
28
|
+
|
29
|
+
@redis.multi do
|
30
|
+
@redis.del(@bucket)
|
31
|
+
@redis.lpush(@bucket, Array.new(constraint[:threshold], Time.now.to_f))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def within_constraints(&block)
|
36
|
+
start_execution
|
37
|
+
yield
|
38
|
+
stop_execution
|
39
|
+
end
|
40
|
+
|
41
|
+
def count_active_executions
|
42
|
+
@constraint[:threshold] - count_free_execution_handles
|
43
|
+
end
|
44
|
+
|
45
|
+
def count_free_execution_handles
|
46
|
+
@redis.llen(@bucket)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def get_execution_handle(subscriber)
|
52
|
+
execution_handle = @redis.lpop(@bucket)
|
53
|
+
unless execution_handle.nil?
|
54
|
+
subscriber.unsubscribe(:new_execution_handle_available)
|
55
|
+
return execution_handle
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def wait_for_execution_handle
|
60
|
+
subscriber = Redis::Namespace.new(:ratelimiter, { :redis => Redis.new })
|
61
|
+
|
62
|
+
subscriber.subscribe(:new_execution_handle_available) do |on|
|
63
|
+
execution_handle = get_execution_handle(subscriber)
|
64
|
+
return execution_handle unless execution_handle.nil?
|
65
|
+
|
66
|
+
on.message do
|
67
|
+
execution_handle = get_execution_handle(subscriber)
|
68
|
+
return execution_handle unless execution_handle.nil?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def start_execution
|
74
|
+
execution_handle = wait_for_execution_handle
|
75
|
+
current_time = Time.now.to_f
|
76
|
+
|
77
|
+
# got next execution handle, wait till it gets valid
|
78
|
+
if execution_handle.to_f > current_time
|
79
|
+
sleep(execution_handle.to_f - current_time)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def stop_execution
|
84
|
+
@redis.multi do
|
85
|
+
@redis.rpush(@bucket, Time.now.to_f + @constraint[:interval])
|
86
|
+
@redis.publish(:new_execution_handle_available, nil)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rate_limited_scheduler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Robert Strobl
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-15 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: This rate-limited scheduler is made for requests to APIs with sensitive,
|
15
|
+
time-critical access restrictions which means that even limits with short time intervals
|
16
|
+
such as 5 requests per second can be hold in a multi-threading environment. It implements
|
17
|
+
Redis-based execution handles.
|
18
|
+
email: mail@rstrobl.com
|
19
|
+
executables: []
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- lib/rate_limited_scheduler.rb
|
24
|
+
homepage: http://github.com/rstrobl/rate_limited_scheduler
|
25
|
+
licenses: []
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 1.8.23
|
45
|
+
signing_key:
|
46
|
+
specification_version: 3
|
47
|
+
summary: A Redis-based rate-limited scheduler for requests to APIs with sensitive
|
48
|
+
and time-critical access restrictions
|
49
|
+
test_files: []
|