Class: MeterCat::Meter
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- MeterCat::Meter
- Defined in:
- app/models/meter_cat/meter.rb
Constant Summary collapse
- DEFAULT_EXPIRATION =
The expiration time for an in-memory cached meter
3600
- DEFAULT_RETRY_ATTEMPTS =
The number of retries in the event of an optimistic locking failure or creation collision
5
- DEFAULT_RETRY_DELAY =
The delay between retries, in seconds. Not using exponential back-off to prevent blocking controllers. Better to lose a little data than create a bad user experience.
1
Class Method Summary collapse
-
.names ⇒ Object
Returns all unique meter names sorted.
-
.random(args) ⇒ Object
Generates a random sequence for a meter given the following args: [ :name, :min, :max, :days ].
-
.set(name, value = 1, created_on = Date.today) ⇒ Object
Sets or creates a new record for the name and day.
-
.to_csv(range, names = nil) ⇒ Object
Returns a CSV where rows represent days.
-
.to_h(range, names = nil) ⇒ Object
Returns a hash of names to dates to values.
Instance Method Summary collapse
-
#add ⇒ Object
Create an object for this name+date in the db if one does not already exist.
-
#add_with_retry ⇒ Object
Calls #add with retry logic up to ::MAX_ADD_ATTEMPTS times.
-
#expired? ⇒ Boolean
Determines if the meter is expired and should be flushed from memory to DB.
Class Method Details
.names ⇒ Object
Returns all unique meter names sorted
71 72 73 |
# File 'app/models/meter_cat/meter.rb', line 71 def self.names Meter.uniq.pluck( :name ).sort.map { |name| name.to_sym } end |
.random(args) ⇒ Object
Generates a random sequence for a meter given the following args:
- :name, :min, :max, :days
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'app/models/meter_cat/meter.rb', line 78 def self.random( args ) name = args[ :name ] min = args[ :min ].to_i max = args[ :max ].to_i stop = Date.today start = Date.today - args[ :days ].to_i (start .. stop).each do |date| value = min + rand( max - min ) begin Meter.create( :name => name, :value => value, :created_on => date ) rescue end end end |
.set(name, value = 1, created_on = Date.today) ⇒ Object
Sets or creates a new record for the name and day
96 97 98 99 100 101 |
# File 'app/models/meter_cat/meter.rb', line 96 def self.set( name, value = 1, created_on = Date.today ) meter = Meter.find_by_name_and_created_on( name, created_on ) meter ||= Meter.new( :name => name, :created_on => created_on ) meter.value = value return meter.save end |
.to_csv(range, names = nil) ⇒ Object
Returns a CSV where rows represent days
137 138 139 140 141 142 143 144 145 146 147 |
# File 'app/models/meter_cat/meter.rb', line 137 def self.to_csv( range, names = nil ) meters = to_h( range, names ) keys = meters.keys.sort! CSV.generate do |csv| csv << [ nil ] + keys range.each do |date| csv << [ date ] + keys.map { |key| meters[ key ][ date ] } end end end |
.to_h(range, names = nil) ⇒ Object
Returns a hash of names to dates to values
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'app/models/meter_cat/meter.rb', line 105 def self.to_h( range, names = nil ) meters = {} # Inject dependencies into the names array calculator = MeterCat.config.calculator calculator.dependencies( names ) if names # Build conditions for the query conditions = {} conditions[ :created_on ] = range if range conditions[ :name ] = names if names # Retrieve the data Meter.select( [ :id, :name, :created_on, :value ] ).where( conditions ).find_each do |meter| name = meter.name.to_sym meters[ name ] ||= {} meters[ name ][ meter.created_on ] = meter.value end # Fill in calculated and missing values calculator.calculate( meters, range, names ) names.each { |name| meters[ name ] ||= {} } if names return meters end |
Instance Method Details
#add ⇒ Object
Create an object for this name+date in the db if one does not already exist. Add the value from this object to the one in the DB. Returns the result of the ActiveRecord save operation.
34 35 36 37 38 39 40 |
# File 'app/models/meter_cat/meter.rb', line 34 def add meter = nil Meter.uncached { meter = Meter.find_by_name_and_created_on( name, created_on )} meter ||= Meter.new( :name => name, :created_on => created_on ) meter.value += value return meter.save end |
#add_with_retry ⇒ Object
Calls #add with retry logic up to ::MAX_ADD_ATTEMPTS times. Catches ActiveRecord::StaleObjectError and ActiveRecord::RecordNotUnique for retries. Returns the result of the final call to #add
46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'app/models/meter_cat/meter.rb', line 46 def add_with_retry success = false (1..MeterCat.config.retry_attempts).each do begin break if success = add rescue ActiveRecord::StaleObjectError, ActiveRecord::RecordNotUnique end Kernel.sleep( MeterCat.config.retry_delay ) end return success end |