Class: RateLimit::BucketBased
- Inherits:
-
Object
- Object
- RateLimit::BucketBased
- Defined in:
- lib/ratelimit/bucketbased.rb,
lib/ratelimit/bucketbased/version.rb
Overview
BucketBased is the star of the show. It takes a storage, a set of configurations, and the name of the default configuration.
storage
-
a method for saving and retrieving buckets (memory, mysql, sqlite3, memcache)
bucket_configs
-
a hash of name => Config pairs
default_bucket_config
-
the name of the default config to choose when automatically creating buckets for items that don’t have buckets
Constant Summary collapse
- VERSION =
"0.0.1"
Instance Attribute Summary collapse
-
#storage ⇒ Object
readonly
Returns the value of attribute storage.
Instance Method Summary collapse
-
#create_bucket(name, config_name = @default_bucket_config) ⇒ Object
- Used primarily to preallocate buckets that need an alternate configuration from the default so that they aren’t automatically created with default configurations
name
- the name of the item to track
config_name
-
the name of the config to use as a template for creating the bucket The new bucket will be saved into the storage for this instance of RateLimiter.
- the name of the item to track
- Used primarily to preallocate buckets that need an alternate configuration from the default so that they aren’t automatically created with default configurations
-
#initialize(storage, bucket_configs, default_bucket_config = 'default') ⇒ BucketBased
constructor
A new instance of BucketBased.
-
#use(name, cost = nil) ⇒ Object
Returns true if the item
name
has enough credits, false otherwise It will automatically create buckets for items that don’t already have buckets and it will do all the bookkeeping to deduct credits, regenerate credits, and track all the credits used.
Constructor Details
#initialize(storage, bucket_configs, default_bucket_config = 'default') ⇒ BucketBased
Returns a new instance of BucketBased.
208 209 210 211 212 213 214 215 216 217 |
# File 'lib/ratelimit/bucketbased.rb', line 208 def initialize(storage, bucket_configs, default_bucket_config='default') @storage = storage @bucket_configs = bucket_configs if @bucket_configs.keys.length == 1 @default_bucket_config = @bucket_configs.keys[0] else @default_bucket_config = default_bucket_config end raise "Cannot find default config" unless @bucket_configs[@default_bucket_config] end |
Instance Attribute Details
#storage ⇒ Object (readonly)
Returns the value of attribute storage.
207 208 209 |
# File 'lib/ratelimit/bucketbased.rb', line 207 def storage @storage end |
Instance Method Details
#create_bucket(name, config_name = @default_bucket_config) ⇒ Object
Used primarily to preallocate buckets that need an alternate configuration from the default so that they aren’t automatically created with default configurations
name
-
the name of the item to track
config_name
-
the name of the config to use as a template for creating the bucket
The new bucket will be saved into the storage for this instance of RateLimiter
223 224 225 226 227 228 |
# File 'lib/ratelimit/bucketbased.rb', line 223 def create_bucket(name, config_name=@default_bucket_config) config = @bucket_configs[config_name] raise "Config is nil" unless config bucket = Bucket.new(name, config.start, config.max, config.min, config.cost, config.refill_amount, config.refill_epoch, Time.now.to_f, 0.0) @storage.set(bucket) end |
#use(name, cost = nil) ⇒ Object
Returns true if the item name
has enough credits, false otherwise It will automatically create buckets for items that don’t already have buckets and it will do all the bookkeeping to deduct credits, regenerate credits, and track all the credits used.
name
-
the name of the item to track
cost
-
the cost of the transaction (defaults to the cost set in the Bucket if nil)
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/ratelimit/bucketbased.rb', line 234 def use(name, cost=nil) # create a bucket using the default config if it doesn't already exist bkt = @storage.get(name) unless bkt create_bucket(name) bkt = @storage.get(name) end unless bkt raise Exception, "Could not find bucket" end # first credit the bucket for the time that has elapsed epochs_elapsed = ((Time.now.to_f - bkt.last_refill)/bkt.refill_epoch).to_i bkt.current += epochs_elapsed * bkt.refill_amount bkt.current = bkt.max if bkt.current > bkt.max bkt.last_refill += epochs_elapsed*bkt.refill_epoch # now see if the bkt has enough to provide service cost ||= bkt.cost # if the cost isn't provided, use the default cost raise "Invalid cost: #{cost}" if cost < 0 enough = bkt.current >= cost # true if sufficient, false if insufficient # track the total costs, but only if service will be rendered bkt.total_used += cost if enough # now deduct the cost, capping at the minimum bkt.current -= cost bkt.current = bkt.min if bkt.current < bkt.min # now save the changes into the storage (if memory, then no changes are needed, we updated the object in memory) @storage.update(bkt) # return the verdict, did they have enough credits to pay the toll? enough end |