tiny_rl 1.2.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tiny_rl.rb +119 -2
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dfd587321069791e9d18bbec07594ae54bef5df6198245fbfb54928a11a22fcc
4
- data.tar.gz: 0be56b681489bb625133a441d3503d2aa5a1591537c278807b47e1bfcaf48d67
3
+ metadata.gz: 9d9dfba7e07aff49aacdce244cf39bc54f87afb03ab40823ee5e7aa56863f80a
4
+ data.tar.gz: fb9a2e33e35858d05da57d5976ab2db87644b694c67ca35df8240b959f0e0580
5
5
  SHA512:
6
- metadata.gz: bb9867ea40155fff57133183c3280c557b64d905a2540ae7d06c7e5944bd9d4bdbd0887220cd2d631d0a16d96ab6779bc97131e1df46f4eed5b606b4bf86ce13
7
- data.tar.gz: fd95d64e2fc4de0801bc9658f2478b73e2f0c1b86633e977af286cc64d96d4885d8a710fa9b7205a20281cb8d94192eee0804464f158b04af52fad57c130ffa9
6
+ metadata.gz: 6b823cdb7a65a0e35a15ef298a383346809a4d443b6132b4221f21c025cdfbd797a95982fabe89a3761d8b601d7cdb120f011c38b783ad0cab09b22033fb8a8c
7
+ data.tar.gz: 80e43f6a8e144cdadf44f3a660960cbb7876c74259d07652dc838de1e8d32ca790684fa8809b1a44b734fa4ac5c69f0bdbaa49dc97acf71121b1ca8a952b152f
data/lib/tiny_rl.rb CHANGED
@@ -1,2 +1,119 @@
1
- require_relative 'tiny_rl/job'
2
- require_relative 'tiny_rl/exec'
1
+ require 'time'
2
+
3
+ # this class simply tracks a rate limit, the timestamps of things you want to
4
+ # limit, and allows you the check both the used capacity and whether or not the
5
+ # rate limit has been reached. there's some additional tracking of the total
6
+ # number of jobs, dropped jobs, and errored jobs, just for some simple
7
+ # accounting.
8
+ #
9
+ # Usage:
10
+ # > rl = TinyRl.new(5, TinyRl::MINUTE, :drop)
11
+ # => <a rate limiter that will drop method calls over a rate of 5 per minute>
12
+ # > 10.times{ rl.track }
13
+ # > rl.used_capacity
14
+ # => 5
15
+ # > rl.at_capacity?
16
+ # => true
17
+ #
18
+ # if you use the :error strategy, then an instance of
19
+ # TinyRl::ExceededRateLimitError will be raised when you exceed the rate limit
20
+ # when calling #track.
21
+ #
22
+ # if you'd like to check the capacity of the TinyRl before taking some action,
23
+ # then check either TinyRl#at_capacity? or TinyRl#used_capacity as appropriate.
24
+ class TinyRl
25
+ STRATEGIES = %i(drop error)
26
+
27
+ SECOND = 1
28
+ MINUTE = SECOND * 60
29
+ HOUR = MINUTE * 60
30
+ DAY = HOUR * 24
31
+ WEEK = DAY * 7
32
+ MONTH = DAY * 30
33
+ YEAR = DAY * 365
34
+
35
+ attr_reader :limit,
36
+ :per,
37
+ :strategy
38
+
39
+ # rate: number of requests per unit time
40
+ # per: unit of time (one of SECOND, MINUTE, etc.)
41
+ # you can pass any integer in as the `per' parameter and it will be
42
+ # interpreted as a number of seconds
43
+ # strategy: what to do when you're over the rate limit
44
+ # drop: drop the request, never perform the method call
45
+ # error: raise an exception when rate exceeded
46
+ def initialize(limit, per, strategy)
47
+ raise TinyRlInvalidStrategyError.new("Strategy `#{strategy.inspect}' is not one of the allowed strategies") unless STRATEGIES.include?(strategy)
48
+ @total_jobs = 0
49
+ @dropped_jobs = 0
50
+ @errored_jobs = 0
51
+ @limit = limit
52
+ @per = per
53
+ @strategy = strategy
54
+
55
+ @job_call_times = []
56
+ end
57
+
58
+ # this method will track the timestamp of something that you want to rate
59
+ # limit. this is generic so that you cand rate limit a bunch of things
60
+ # collectively with a single TinyRl instance.
61
+ #
62
+ # for strategy :drop
63
+ # returns true if the job was run, false if it was dropped
64
+ # for strategy :error
65
+ # returns true if the job was run, raises an exception otherwise
66
+ def track
67
+ @total_jobs += 1
68
+
69
+ if at_capacity?
70
+ case @strategy
71
+ when :drop
72
+ @dropped_jobs += 1
73
+ when :error
74
+ @errored_jobs += 1
75
+ raise TinyRlExceededRateLimitError.new("Rate limit of #{@limit} per #{@per} sec exceeded")
76
+ end
77
+ false
78
+ else
79
+ @job_call_times << Time.now
80
+ true
81
+ end
82
+ end
83
+
84
+ # returns true if the rate limit has currently been reached, false otherwise
85
+ def at_capacity?
86
+ _clear_old_jobs
87
+ @job_call_times.length == @limit
88
+ end
89
+
90
+ # useful for monitoring by consuming programs, and for issuing warnings when
91
+ # you're close, but not over, your limit
92
+ def used_capacity
93
+ _clear_old_jobs
94
+ @job_call_times.length
95
+ end
96
+
97
+ # removes old jobs before. used before checking capacity
98
+ def _clear_old_jobs
99
+ loop do
100
+ break if (@job_call_times.length == 0) || (@job_call_times.first >= (Time.now - @per))
101
+ @job_call_times.shift
102
+ end
103
+ end
104
+
105
+ # for debugging, really
106
+ def to_s
107
+ <<~TO_S
108
+ limit: #{@limit} per #{@per} seconds
109
+ at_capacity?: #{at_capacity?}
110
+ used_capacity: #{used_capacity}
111
+ total_jobs: #{@total_jobs}
112
+ dropped_jobs: #{@dropped_jobs}
113
+ errored_jobs: #{@errored_jobs}
114
+ TO_S
115
+ end
116
+ end
117
+
118
+ class TinyRlExceededRateLimitError < RuntimeError; end
119
+ class TinyRlInvalidStrategyError < RuntimeError; end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tiny_rl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Lunt