drone 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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