elected_scheduler 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 80e36753deee16c6d4ac311880ddf160076f5d60
4
- data.tar.gz: 899d8490b59f93ebc242788a303f5084ebe3775a
3
+ metadata.gz: 65e11fc03001777e3fc15d10cf8f617ccfc7c76e
4
+ data.tar.gz: b21d8aa9b54dd3858a097e45bacdc2c3333227d7
5
5
  SHA512:
6
- metadata.gz: 938a658a6c1f60910b09e0f7ca214f8b96b139b15b251593e4bef4ae11919bb352eb29cf1b5d07ec53bcaed9337a163baed2cad4d761ac7b32668cafdee8388d
7
- data.tar.gz: 9cf6aace4ec6d692d300f1af6b292a579697fa2fbb4cd22756e2fb4ae67dd17fcd357c8889afbfbdf9f2c2bdd6d8db6a6019e2adce6023d6ee8c29011181f3e0
6
+ metadata.gz: 0261d2074e5ac4e60f0f2bdc28f719775668eb6c403cb66c2663779c543da6bbc87db6ad646f785375b06052d5bc29f1e2cdc050c227096b1ddeda0a02299730
7
+ data.tar.gz: b946425a46a34668698a89555ffbe345d79e60a417a6dbb07f2462069d924d233a343ef3d54560a357e4ce5a89f3afdd68c6fb4d36ee469cf43bc63438494e1d
data/README.md CHANGED
@@ -1,3 +1,8 @@
1
+ [![Build Status](https://travis-ci.org/simple-finance/elected_scheduler.svg?branch=master)](https://travis-ci.org/simple-finance/elected_scheduler)
2
+ [![Code Climate](https://codeclimate.com/github/simple-finance/elected_scheduler/badges/gpa.svg)](https://codeclimate.com/github/simple-finance/elected_scheduler)
3
+ [![security](https://hakiri.io/github/simple-finance/elected_scheduler/master.svg)](https://hakiri.io/github/simple-finance/elected_scheduler/master)
4
+ [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/simple-finance/elected_scheduler?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
5
+
1
6
  # ElectedScheduler - A ruby distributed cron-like scheduler that only runs jobs on leader processes.
2
7
 
3
8
  > Schedule your jobs at cron-like times (seconds included) and run the jobs only if the process is the current leader.
@@ -5,7 +5,7 @@ module Elected
5
5
  include Logging
6
6
  extend Forwardable
7
7
 
8
- attr_reader :key, :jobs
8
+ attr_reader :key, :jobs, :stats
9
9
 
10
10
  def_delegators :@senado, :timeout
11
11
 
@@ -13,6 +13,7 @@ module Elected
13
13
  @senado ||= Senado.new key, timeout
14
14
  @key = key
15
15
  @jobs = Concurrent::Hash.new
16
+ @stats = Stats.new :processed_job, :no_match, :sleep_slave
16
17
  end
17
18
 
18
19
  def add(job)
@@ -26,27 +27,17 @@ module Elected
26
27
  @status ||= :stopped
27
28
  end
28
29
 
29
- def starting?
30
- status == :starting
31
- end
32
-
33
30
  def running?
34
31
  status == :running
35
32
  end
36
33
 
37
- def stopping?
38
- status == :stopping
39
- end
40
-
41
34
  def stopped?
42
35
  status == :stopped
43
36
  end
44
37
 
45
38
  def start
46
- unless stopped?
47
- debug "cannot start on #{status} ..."
48
- return false
49
- end
39
+ return false unless stopped?
40
+ raise 'No jobs to run!' if jobs.empty?
50
41
 
51
42
  debug "#{label} starting ..."
52
43
  @status = :starting
@@ -54,24 +45,24 @@ module Elected
54
45
  @status = :running
55
46
  debug "#{label} running poller!"
56
47
  @status
57
- rescue Exception => e
58
- error "#{label} Exception thrown: #{e.class.name} : #{e.message}\n #{e.backtrace[0, 5].join("\n ")}"
59
48
  end
60
49
 
61
50
  def stop
62
- unless running?
63
- warn "cannot stop on #{status} ..."
64
- return false
65
- end
51
+ return false unless running?
66
52
 
67
53
  debug "#{label} stopping poller ..."
68
54
  @status = :stopping
69
55
  stop_polling_loop
56
+ senado.release
70
57
  @status = :stopped
71
58
  debug "#{label} stopped poller!"
72
59
  @status
73
60
  end
74
61
 
62
+ def leader?
63
+ senado.leader?
64
+ end
65
+
75
66
  def to_s
76
67
  %{#<#{self.class.name} key="#{key}" timeout="#{timeout}" jobs=#{jobs.size}>}
77
68
  end
@@ -85,11 +76,7 @@ module Elected
85
76
  def start_polling_loop
86
77
  debug 'starting process loop ...'
87
78
  @polling_loop_thread = Thread.new do
88
- begin
89
- poll_and_process_loop
90
- rescue Exception => e
91
- error "Exception: #{e.class.name} : #{e.message}\n #{e.backtrace[0, 10].join("\n ")}"
92
- end
79
+ poll_and_process_loop
93
80
  end
94
81
  end
95
82
 
@@ -97,29 +84,32 @@ module Elected
97
84
  cnt = 0
98
85
  while running?
99
86
  cnt += 1
100
- begin
101
- debug "#{label(cnt)} calling poll_and_process_jobs while running?:#{running?} ..."
102
- poll_and_process_jobs
103
- rescue Exception => e
104
- error "#{label(cnt)} Exception: #{e.class.name} : #{e.message}\n #{e.backtrace[0, 5].join("\n ")}"
105
- end
87
+ debug "#{label(cnt)} calling poll_and_process_jobs while running?:#{running?} ..."
88
+ poll_and_process_jobs
106
89
  sleep_until_next_tick
107
90
  end
108
91
  end
109
92
 
110
93
  def poll_and_process_jobs
111
94
  if senado.leader?
95
+ debug "#{label} leader, processing jobs ..."
112
96
  start_time = Time.now
113
97
  jobs.values.each { |job| process_job job, start_time }
114
98
  else
99
+ debug "#{label} not a leader, sleeping ..."
100
+ @stats.increment :sleep_slave
115
101
  sleep_for_slave
116
102
  end
117
103
  end
118
104
 
119
105
  def process_job(job, time)
120
- return false unless job.matches? time
106
+ unless job.matches? time
107
+ @stats.increment :no_match
108
+ return false
109
+ end
121
110
 
122
111
  Concurrent::Future.execute { job.execute }
112
+ @stats.increment :processed_job
123
113
  end
124
114
 
125
115
  def stop_polling_loop
@@ -147,8 +137,18 @@ module Elected
147
137
 
148
138
  extend self
149
139
 
140
+ attr_writer :key, :timeout
141
+
142
+ def key
143
+ @key || 'elected_scheduler_poller'
144
+ end
145
+
146
+ def timeout
147
+ @timeout || Elected.timeout
148
+ end
149
+
150
150
  def poller
151
- @poller ||= Poller.new
151
+ @poller ||= Poller.new key, timeout
152
152
  end
153
153
  end
154
154
  end
@@ -6,11 +6,14 @@ module Elected
6
6
 
7
7
  FIELDS = { seconds: :sec, minutes: :min, hours: :hour, days: :day, months: :month, dows: :wday }.freeze
8
8
 
9
- ABBR_DAYNAMES = %w{ sun mon tue wed thu fri sat }
10
- DAYNAMES = %w{ sunday monday tuesday wednesday thursday friday saturday }
9
+ ABBR_DAYNAMES = %w{ sun mon tue wed thu fri sat }.freeze
10
+ DAYNAMES = %w{ sunday monday tuesday wednesday thursday friday saturday }.freeze
11
11
 
12
- MONTHNAMES = %w{ january february march april may june july august september october november december }
13
- ABBR_MONTHNAMES = %w{ jan feb mar apr may jun jul aug sep oct nov dec }
12
+ MONTHNAMES = %w{ '' january february march april may june july august september october november december }.freeze
13
+ ABBR_MONTHNAMES = %w{ '' jan feb mar apr may jun jul aug sep oct nov dec }.freeze
14
+
15
+ MIN_NUMBERS = { seconds: 0, minutes: 0, hours: 0, days: 1, months: 1, dows: 0 }.freeze
16
+ MAX_NUMBERS = { seconds: 59, minutes: 59, hours: 23, days: 31, months: 12, dows: 6 }.freeze
14
17
 
15
18
  def self.defaults
16
19
  @defaults ||= { seconds: [0] }
@@ -18,7 +21,7 @@ module Elected
18
21
 
19
22
  def initialize(options = {})
20
23
  @options = options
21
- setup *FIELDS.keys
24
+ setup *(FIELDS.keys)
22
25
  end
23
26
 
24
27
  def matches?(time)
@@ -26,15 +29,7 @@ module Elected
26
29
  end
27
30
 
28
31
  def to_cron_s
29
- FIELDS.keys.map do |field|
30
- value = get field
31
- case value
32
- when :all
33
- '*'
34
- when Range, Array
35
- value.map { |x| x.to_s }.join(',')
36
- end
37
- end.join(' ')
32
+ FIELDS.keys.map { |field| get_cron_s(field) }.join(' ')
38
33
  end
39
34
 
40
35
  alias :to_s :to_cron_s
@@ -48,6 +43,11 @@ module Elected
48
43
 
49
44
  alias :[] :get
50
45
 
46
+ def get_cron_s(field)
47
+ value = get(field)
48
+ value === :all ? '*' : value.map { |x| x.to_s }.join(',')
49
+ end
50
+
51
51
  def set(field, value)
52
52
  instance_variable_set "@#{field}", convert(field, value)
53
53
  end
@@ -65,102 +65,48 @@ module Elected
65
65
  end
66
66
 
67
67
  def convert(field, value)
68
+ return value if value === :all
69
+
70
+ ary = simplify_enum Array(value).flatten
68
71
  case field
69
72
  when :seconds, :minutes, :hours, :days
70
- convert_numbers field, value
73
+ convert_numbers field, ary
71
74
  when :months
72
- convert_months value
75
+ convert_numbers :months, ary, :convert_month_name
73
76
  when :dows
74
- convert_dows value
77
+ convert_numbers :dows, ary, :convert_dow_name
75
78
  end
76
79
  end
77
80
 
78
- def match?(field, exp_value)
79
- value = get field
80
- return true if value === :all
81
- value.include? exp_value
81
+ def simplify_enum(ary)
82
+ ary.map { |x| x.is_a?(Range) ? x.to_a : x }.flatten
82
83
  end
83
84
 
84
- def convert_numbers(field, value)
85
- max = { seconds: 60, minutes: 60, hours: 23, days: 31 }[field]
86
- case value
87
- when :all
88
- value
89
- when Integer
90
- simplify_enum [value], 0, max
91
- when Array, Range
92
- simplify_enum value, 0, max
93
- else
94
- raise "Unknown value (#{value.class.name}) #{value.inspect}] for #{field}"
95
- end
85
+ def convert_numbers(field, ary, converter_name = nil)
86
+ ary.map do |x|
87
+ converter_name ? send(converter_name, x) : x
88
+ end.select do |x|
89
+ x.is_a?(Integer) && x >= MIN_NUMBERS[field] && x <= MAX_NUMBERS[field]
90
+ end.uniq.sort
96
91
  end
97
92
 
98
- def simplify_enum(ary, min, max)
99
- ary.to_a.flatten.map do |x|
100
- x.is_a?(Range) ? simplify_enum(x.to_a, min, max) : x.to_i
101
- end.flatten.uniq.sort.
102
- select { |x| x >= min && x <= max }
103
- end
93
+ def convert_month_name(value)
94
+ return value unless value.is_a?(String) || value.is_a?(Symbol)
104
95
 
105
- def convert_months(value)
106
- case value
107
- when :all
108
- value
109
- when Integer, Symbol, String
110
- convert_months [value]
111
- when Array, Range
112
- ary = value.map { |x| convert_month x }
113
- simplify_enum ary, 1, 12
114
- else
115
- raise "Unknown value (#{value.class.name}) #{value.inspect}] for month"
116
- end
96
+ [ABBR_MONTHNAMES, MONTHNAMES].map { |ary| ary.index value.to_s.downcase }.compact.first
117
97
  end
118
98
 
119
- def convert_month(value)
120
- case value
121
- when Integer
122
- raise "Unknown value (#{value.class.name}) #{value.inspect}] for month" if value < 1 || value > 12
123
- value
124
- when Array, Range
125
- ary = value.map { |x| convert_month x }
126
- simplify_enum ary, 1, 12
127
- when String, Symbol
128
- idx = [ABBR_MONTHNAMES, MONTHNAMES].map { |ary| ary.index value.to_s.downcase }.compact.first
129
- raise "[#{idx}] Unknown value (#{value.class.name}) #{value.inspect}] for month" if idx.nil? || idx < 0 || idx > 11
130
- idx + 1
131
- else
132
- raise "Unknown value (#{value.class.name}) #{value.inspect}] for month"
133
- end
134
- end
99
+ def convert_dow_name(value)
100
+ return value unless value.is_a?(String) || value.is_a?(Symbol)
135
101
 
136
- def convert_dows(value)
137
- case value
138
- when :all
139
- value
140
- when Integer, Symbol, String
141
- convert_dows [value]
142
- when Array, Range
143
- ary = value.map { |x| convert_dow x }
144
- simplify_enum ary, 0, 6
145
- else
146
- raise "Unknown value (#{value.class.name}) #{value.inspect}] for dow"
147
- end
102
+ [ABBR_DAYNAMES, DAYNAMES].map { |ary| ary.index value.to_s.downcase }.compact.first
148
103
  end
149
104
 
150
- def convert_dow(value)
151
- case value
152
- when Integer
153
- value
154
- when Array, Range
155
- ary = value.map { |x| convert_dow x }
156
- simplify_enum ary, 0, 6
157
- when String, Symbol
158
- idx = [ABBR_DAYNAMES, DAYNAMES].map { |ary| ary.index value.to_s.downcase }.compact.first
159
- raise "[#{idx}] Unknown value (#{value.class.name}) #{value.inspect}] for dow" if idx.nil? || idx < 0 || idx > 6
160
- idx
161
- else
162
- raise "Unknown value (#{value.class.name}) #{value.inspect}] for dow"
163
- end
105
+ def match?(field, exp_value)
106
+ value = get field
107
+ return true if value === :all
108
+
109
+ value.include? exp_value
164
110
  end
165
111
 
166
112
  end
@@ -1,5 +1,5 @@
1
1
  module Elected
2
2
  module Scheduler
3
- VERSION = '0.1.0'
3
+ VERSION = '0.1.1'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elected_scheduler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrian Madrid
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-30 00:00:00.000000000 Z
11
+ date: 2015-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: elected