Class: MeterCat::Meter

Inherits:
ActiveRecord::Base
  • Object
show all
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

Instance Method Summary collapse

Class Method Details

.namesObject

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

#addObject

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_retryObject

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

#expired?Boolean

Determines if the meter is expired and should be flushed from memory to DB

Returns:

  • (Boolean)


62
63
64
# File 'app/models/meter_cat/meter.rb', line 62

def expired?
  return ( Time.now - created_at ) > MeterCat.config.expiration
end