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.
Files changed (2) hide show
  1. data/lib/rate_limited_scheduler.rb +89 -0
  2. 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: []