drone 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,107 +0,0 @@
1
- require File.expand_path('../metrics/meter', __FILE__)
2
- require File.expand_path('../metrics/timer', __FILE__)
3
-
4
- module Drone
5
- ##
6
- # This module contains what is needed to instruments
7
- # class methods easily
8
- #
9
- module Monitoring
10
- def self.included(base)
11
- base.class_eval do
12
- extend ClassMethods
13
- end
14
-
15
- Drone::register_monitored_class(base)
16
- end
17
-
18
- module ClassMethods
19
- # external API
20
-
21
- ##
22
- # Monitor the call rate of the following method
23
- #
24
- # @param [String] name metric name, it must be unique and will be shared
25
- # among all the objects of this class
26
- # @api public
27
- #
28
- def monitor_rate(name)
29
- meter = Drone::find_metric(name) || Metrics::Meter.new(name)
30
- unless meter.is_a?(Metrics::Meter)
31
- raise(TypeError, "metric #{name} is already defined as #{rate.class}")
32
- end
33
-
34
- Drone::register_metric(meter)
35
- @_rate_waiting = meter
36
- end
37
-
38
- ##
39
- # Monitor the time of execution as well as the
40
- # call rate
41
- #
42
- # @param [String] name metric name, it must be unique and will be shared
43
- # among all the objects of this class
44
- #
45
- # @api public
46
- #
47
- def monitor_time(name)
48
- timer = Drone::find_metric(name) || Metrics::Timer.new(name)
49
- unless timer.is_a?(Metrics::Timer)
50
- raise(TypeError, "metric #{name} is already defined as #{rate.class}")
51
- end
52
- Drone::register_metric(timer)
53
- @_timer_waiting = timer
54
- end
55
-
56
-
57
- # internals
58
-
59
- ##
60
- # @private
61
- #
62
- def method_added(m)
63
- return if @_ignore_added
64
-
65
- @_ignore_added = true
66
- ma_rate_meter(m) if @_rate_waiting
67
- ma_timer_meter(m) if @_timer_waiting
68
- @_ignore_added = false
69
- end
70
-
71
- ##
72
- # @private
73
- #
74
- def ma_rate_meter(m)
75
- rate = @_rate_waiting
76
- @_rate_waiting = nil
77
-
78
- define_method("#{m}_with_meter") do |*args, &block|
79
- rate.mark()
80
- send("#{m}_without_meter", *args, &block)
81
- end
82
-
83
- alias_method "#{m}_without_meter", m
84
- alias_method m, "#{m}_with_meter"
85
- end
86
-
87
- ##
88
- # @private
89
- #
90
- def ma_timer_meter(m)
91
- timer = @_timer_waiting
92
- @_timer_waiting = nil
93
-
94
- define_method("#{m}_with_timer") do |*args, &block|
95
- timer.time do
96
- send("#{m}_without_timer", *args, &block)
97
- end
98
- end
99
-
100
- alias_method "#{m}_without_timer", m
101
- alias_method m, "#{m}_with_timer"
102
- end
103
-
104
- end
105
-
106
- end
107
- end
@@ -1,70 +0,0 @@
1
- require 'eventmachine'
2
-
3
- module Drone
4
- module Schedulers
5
- module EMScheduler
6
-
7
- @started = false
8
- @timers_once = []
9
- @timers_periodic = []
10
-
11
- ##
12
- # Schedule a block to be called immediatly and after
13
- # that at a specified interval
14
- #
15
- # @param [Number] delay the interval
16
- #
17
- def self.schedule_periodic(delay, &block)
18
- raise "Block required" unless block
19
- if @started
20
- block.call()
21
- EM::add_periodic_timer(delay, &block)
22
- else
23
- @timers_periodic << [delay, block]
24
- end
25
- end
26
-
27
-
28
- ##
29
- # Schedule a block to be called after a specified
30
- # delay
31
- #
32
- # @param [Number] delay the interval
33
- #
34
- def self.schedule_once(delay, &block)
35
- raise "Block required" unless block
36
- if @started
37
- EM::add_timer(delay, &block)
38
- else
39
- @timers_once << [delay, block]
40
- end
41
- end
42
-
43
-
44
- ##
45
- # Start the timers.
46
- #
47
- def self.start
48
- @started = true
49
- @timers_once.each do |(delay, block)|
50
- schedule_once(delay, &block)
51
- end
52
-
53
- @timers_periodic.each do |(delay, block)|
54
- schedule_periodic(delay, &block)
55
- end
56
-
57
- end
58
-
59
- ##
60
- # @private
61
- #
62
- def self.reset
63
- @timers_once.clear()
64
- @timers_periodic.clear()
65
- @started = false
66
- end
67
-
68
- end
69
- end
70
- end
@@ -1,122 +0,0 @@
1
- module Drone
2
- module Storage
3
-
4
- ##
5
- # Represents a number but procide a specific api
6
- # allowing this number to shared anywhere
7
- #
8
- class SharedNumber
9
- ##
10
- # Constructor
11
- #
12
- # @param [Number] initial_value The initial value
13
- #
14
- def initialize(initial_value)
15
- raise "needs to be redefined"
16
- end
17
-
18
- ##
19
- # Increment the value
20
- #
21
- # @param [Number] n Increment by n
22
- #
23
- def inc(n = 1)
24
- raise "needs to be redefined"
25
- end
26
-
27
- ##
28
- # Decrement the value
29
- #
30
- # @param [Number] n Decrement by n
31
- #
32
- def dec(n = 1)
33
- raise "needs to be redefined"
34
- end
35
-
36
- ##
37
- # Set the value
38
- #
39
- # @param [Number] n The new value
40
- #
41
- def set(n)
42
- raise "needs to be redefined"
43
- end
44
-
45
- ##
46
- # Get the current value
47
- #
48
- # @return [Number] The current value
49
- #
50
- def get
51
- raise "needs to be redefined"
52
- end
53
-
54
- ##
55
- # Set a new value and return the old one
56
- #
57
- # @param [Number] n The new value
58
- #
59
- # @return [Number] The old value
60
- #
61
- def get_and_set(n)
62
- raise "needs to be redefined"
63
- end
64
-
65
- ##
66
- # Set the new value but only if the current value
67
- # is equal to expected.
68
- #
69
- # @param [Number] expected The expected current value
70
- # @param [Number] new_value The new value
71
- #
72
- def compare_and_set(expected, new_value)
73
- raise "needs to be redefined"
74
- end
75
-
76
- end
77
-
78
- class Base
79
-
80
- ##
81
- # Request a fixed size array.
82
- #
83
- # @param [String] id Any string which makes sense in the context
84
- # @param [Number] size The Array size
85
- # @param [Number] initial_value The default value for the cells
86
- #
87
- # @return [Object] Returns an object which share the same external interface as
88
- # the Array class
89
- #
90
- def request_fixed_size_array(id, size, initial_value = nil)
91
- raise "needs to be redefined"
92
- end
93
-
94
- ##
95
- # Request a hash.
96
- #
97
- # @param [String] id Any string which makes sense in the context
98
- #
99
- # @return [Object] Returns an object which share the same external interface as
100
- # the Hash class
101
- #
102
- def request_hash(id)
103
- raise "needs to be redefined"
104
- end
105
-
106
- ##
107
- # Request a number "slot".
108
- #
109
- # @param [String] id Any string which makes sense in the context
110
- # @param [Number] initial_value The intial value
111
- #
112
- # @return [SharedNumber] An intance of a class inheriting SharedNumber
113
- #
114
- # @see SharedNumber
115
- #
116
- def request_number(id, initial_value = 0)
117
- raise "needs to be redefined"
118
- end
119
- end
120
-
121
- end
122
- end
@@ -1,58 +0,0 @@
1
- require File.expand_path('../base', __FILE__)
2
-
3
- module Drone
4
- module Storage
5
-
6
- class Memory < Base
7
-
8
- class MemorySharedNumber
9
- def initialize(initial_value)
10
- @store = initial_value
11
- end
12
-
13
- def inc(n = 1)
14
- @store += n
15
- end
16
-
17
- def dec(n = 1)
18
- @store -= n
19
- end
20
-
21
- def set(n)
22
- @store = n
23
- end
24
-
25
- def get
26
- @store
27
- end
28
-
29
- def get_and_set(n)
30
- ret = @store
31
- set(n)
32
- ret
33
- end
34
-
35
- def compare_and_set(expected, new_value)
36
- # dummy implementation, with memory storage nothing can
37
- # happen to our data
38
- set(new_value)
39
- end
40
-
41
- end
42
-
43
- def request_fixed_size_array(id, size, initial_value = nil)
44
- Array.new(size, initial_value)
45
- end
46
-
47
- def request_hash(id)
48
- Hash.new
49
- end
50
-
51
- def request_number(id, initial_value = 0)
52
- MemorySharedNumber.new(initial_value)
53
- end
54
-
55
- end
56
-
57
- end
58
- end
@@ -1,55 +0,0 @@
1
- require File.expand_path('../../core', __FILE__)
2
-
3
- module Drone
4
- class EWMA
5
- M1_ALPHA = (1 - Math.exp(-5 / 60.0)).freeze
6
- M5_ALPHA = (1 - Math.exp(-5 / 60.0 / 5)).freeze
7
- M15_ALPHA = (1 - Math.exp(-5 / 60.0 / 15)).freeze
8
-
9
- def self.one_minute_ewma(id)
10
- new(id, M1_ALPHA, 5000)
11
- end
12
-
13
- def self.five_minutes_ewma(id)
14
- new(id, M5_ALPHA, 5000)
15
- end
16
-
17
- def self.fifteen_minutes_ewma(id)
18
- new(id, M15_ALPHA, 5000)
19
- end
20
-
21
-
22
- # interval: in ms
23
- def initialize(name, alpha, interval)
24
- @alpha = alpha
25
- @interval = interval.to_f # * (1000*1000)
26
- @uncounted = Drone::request_number("#{name}:uncounted", 0)
27
- @rate = Drone::request_number("#{name}:rate", nil)
28
- end
29
-
30
- def update(n)
31
- @uncounted.inc(n)
32
- end
33
-
34
- def tick()
35
- count = @uncounted.get_and_set(0)
36
-
37
- instant_rate = count / @interval
38
- rate = @rate.get
39
-
40
- if rate
41
- @rate.inc( @alpha * (instant_rate - rate) )
42
- else
43
- @rate.set( instant_rate )
44
- end
45
- end
46
-
47
- def rate(as = :seconds)
48
- case as
49
- when :ms then @rate.get
50
- when :seconds then @rate.get * 1000
51
- end
52
- end
53
-
54
- end
55
- end
@@ -1,81 +0,0 @@
1
- require File.expand_path('../../core', __FILE__)
2
-
3
- module Drone
4
- class ExponentiallyDecayingSample
5
- # 1 hour in ms
6
- RESCALE_THRESHOLD = (1 * 60 * 60 * 1000).freeze
7
-
8
- def initialize(id, reservoir_size, alpha)
9
- @id = id
10
- @values = Drone::request_hash("#{@id}:values")
11
- @count = Drone::request_number("#{@id}:count", 0)
12
- @start_time = Drone::request_number("#{@id}:start_time", current_time())
13
- @next_scale_time = Drone::request_number("#{@id}:next_scale_time", current_time() + RESCALE_THRESHOLD)
14
-
15
- @alpha = alpha
16
- @reservoir_size = reservoir_size
17
- end
18
-
19
- def clear
20
- @values.clear()
21
- @count.set(0)
22
- @start_time.set(current_time())
23
- @next_scale_time.set( current_time() + RESCALE_THRESHOLD )
24
- end
25
-
26
- def size
27
- count = @count.get
28
- (@values.size < count) ? @values.size : count
29
- end
30
-
31
-
32
- def update(val, time = current_time)
33
- priority = weight(time - @start_time.get) / rand()
34
- count = @count.inc
35
- if count <= @reservoir_size
36
- @values[priority] = val
37
- else
38
- first = @values.keys.min
39
- if first < priority
40
- @values[priority] = val
41
- while @values.delete(first) == nil
42
- first = @values.keys.min
43
- end
44
- end
45
- end
46
-
47
- now = current_time()
48
- if now >= @next_scale_time.get
49
- rescale(now)
50
- end
51
- end
52
-
53
- def values
54
- @values.keys.sort.inject([]) do |buff, key|
55
- buff << @values[key]
56
- end
57
- end
58
-
59
- def rescale(now)
60
- @next_scale_time.set( current_time() + RESCALE_THRESHOLD )
61
- new_start = current_time()
62
- old_start = @start_time.get_and_set(new_start)
63
-
64
- @values = Hash[ @values.map{ |k,v|
65
- [k * Math.exp(-@alpha * (new_start - old_start)), v]
66
- }]
67
-
68
- end
69
-
70
- private
71
-
72
- def current_time
73
- Time.now.to_f * 1000
74
- end
75
-
76
- def weight(n)
77
- Math.exp(@alpha * n)
78
- end
79
-
80
- end
81
- end