tiny_rl 1.2.0 → 2.0.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 +115 -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: 2ff77bc53d01edfc80ddab66a55e6cca3333bb943199b8e707796fb950423bed
4
+ data.tar.gz: 0cee04760a9250243b7bcb715d437d958fa8d9ff0deb8d5df169d5972c05c695
5
5
  SHA512:
6
- metadata.gz: bb9867ea40155fff57133183c3280c557b64d905a2540ae7d06c7e5944bd9d4bdbd0887220cd2d631d0a16d96ab6779bc97131e1df46f4eed5b606b4bf86ce13
7
- data.tar.gz: fd95d64e2fc4de0801bc9658f2478b73e2f0c1b86633e977af286cc64d96d4885d8a710fa9b7205a20281cb8d94192eee0804464f158b04af52fad57c130ffa9
6
+ metadata.gz: 37640f7aeaa30e0f65f082a50501d6a6b6f1f538f2c20424e18d5c6eeeb4ebab33a1414aaa743272dd4363c59b8ce3774c37f01e9cdd2adf9596719305fc84d2
7
+ data.tar.gz: f52bad20a8ec1c15438d8c66a649ab4d6b1faa522d4f3b853d4228e09206d36267f3cf1d88b91d8fdb353b5a513d5cc67c7a77aab0fc67fac2f2c9739e63a27f
data/lib/tiny_rl.rb CHANGED
@@ -1,2 +1,115 @@
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
+ # rate: number of requests per unit time
36
+ # per: unit of time (one of SECOND, MINUTE, etc.)
37
+ # you can pass any integer in as the `per' parameter and it will be
38
+ # interpreted as a number of seconds
39
+ # strategy: what to do when you're over the rate limit
40
+ # drop: drop the request, never perform the method call
41
+ # error: raise an exception when rate exceeded
42
+ def initialize(limit, per, strategy)
43
+ raise TinyRlInvalidStrategyError.new("Strategy `#{strategy.inspect}' is not one of the allowed strategies") unless STRATEGIES.include?(strategy)
44
+ @total_jobs = 0
45
+ @dropped_jobs = 0
46
+ @errored_jobs = 0
47
+ @limit = limit
48
+ @per = per
49
+ @strategy = strategy
50
+
51
+ @job_call_times = []
52
+ end
53
+
54
+ # this method will track the timestamp of something that you want to rate
55
+ # limit. this is generic so that you cand rate limit a bunch of things
56
+ # collectively with a single TinyRl instance.
57
+ #
58
+ # for strategy :drop
59
+ # returns true if the job was run, false if it was dropped
60
+ # for strategy :error
61
+ # returns true if the job was run, raises an exception otherwise
62
+ def track
63
+ @total_jobs += 1
64
+
65
+ if at_capacity?
66
+ case @strategy
67
+ when :drop
68
+ @dropped_jobs += 1
69
+ when :error
70
+ @errored_jobs += 1
71
+ raise TinyRlExceededRateLimitError.new("Rate limit of #{@limit} per #{@per} sec exceeded")
72
+ end
73
+ false
74
+ else
75
+ @job_call_times << Time.now
76
+ true
77
+ end
78
+ end
79
+
80
+ # returns true if the rate limit has currently been reached, false otherwise
81
+ def at_capacity?
82
+ _clear_old_jobs
83
+ @job_call_times.length == @limit
84
+ end
85
+
86
+ # useful for monitoring by consuming programs, and for issuing warnings when
87
+ # you're close, but not over, your limit
88
+ def used_capacity
89
+ _clear_old_jobs
90
+ @job_call_times.length
91
+ end
92
+
93
+ # removes old jobs before. used before checking capacity
94
+ def _clear_old_jobs
95
+ loop do
96
+ break if (@job_call_times.length == 0) || (@job_call_times.first >= (Time.now - @per))
97
+ @job_call_times.shift
98
+ end
99
+ end
100
+
101
+ # for debugging, really
102
+ def to_s
103
+ <<~TO_S
104
+ limit: #{@limit} per #{@per} seconds
105
+ at_capacity?: #{at_capacity?}
106
+ used_capacity: #{used_capacity}
107
+ total_jobs: #{@total_jobs}
108
+ dropped_jobs: #{@dropped_jobs}
109
+ errored_jobs: #{@errored_jobs}
110
+ TO_S
111
+ end
112
+ end
113
+
114
+ class TinyRlExceededRateLimitError < RuntimeError; end
115
+ 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.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Lunt