shoryuken-later 0.0.5.4 → 0.0.6
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.
- checksums.yaml +4 -4
- data/Rakefile +0 -0
- data/lib/shoryuken/later/cli.rb +35 -44
- data/lib/shoryuken/later/poller.rb +5 -13
- data/lib/shoryuken/later/version.rb +2 -2
- data/shoryuken-later.gemspec +1 -1
- data/spec/shoryuken/later/poller_spec.rb +2 -16
- data/spec/spec_helper.rb +0 -2
- metadata +4 -6
- data/lib/shoryuken/later/launcher.rb +0 -44
- data/lib/shoryuken/later/manager.rb +0 -139
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ed2b69dae97667b38ef15a0be1ee0f6989e9c95
|
4
|
+
data.tar.gz: 82fa4cb2cb2f763be48094df3f4224a025d56815
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f1d6efd2b3521a763e685e65d3c695fa8282ab6f3b0b4b0dc6450d26a0b656ffffaf40057db9bf35cee63ac1f9708715649581ff0094ddf2d0bd707a195cf02
|
7
|
+
data.tar.gz: f5f07fd722f05fc37206b8e4a59e1acf2960282a7656d60275df746458b60bbf0b3be0e2e82d649fd5ae4fefc0875025cfd84d4e839bb45927c20f38453d706a
|
data/Rakefile
CHANGED
File without changes
|
data/lib/shoryuken/later/cli.rb
CHANGED
@@ -7,6 +7,7 @@ require 'singleton'
|
|
7
7
|
require 'optparse'
|
8
8
|
require 'erb'
|
9
9
|
require 'shoryuken/later'
|
10
|
+
require 'timers'
|
10
11
|
|
11
12
|
module Shoryuken
|
12
13
|
module Later
|
@@ -14,8 +15,6 @@ module Shoryuken
|
|
14
15
|
include Shoryuken::Util
|
15
16
|
include Singleton
|
16
17
|
|
17
|
-
attr_accessor :launcher
|
18
|
-
|
19
18
|
def run(args)
|
20
19
|
self_read, self_write = IO.pipe
|
21
20
|
|
@@ -34,38 +33,47 @@ module Shoryuken
|
|
34
33
|
validate!
|
35
34
|
daemonize
|
36
35
|
write_pid
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
36
|
+
|
37
|
+
logger.info 'Starting'
|
38
|
+
|
39
|
+
# Initialize the timers and poller.
|
40
|
+
@timers = Timers::Group.new
|
41
|
+
require 'shoryuken/later/poller'
|
42
|
+
@pollers = Shoryuken::Later.tables.map{|tbl| Poller.new(tbl) }
|
43
|
+
|
42
44
|
begin
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
# Poll for items on startup, and every :poll_delay
|
46
|
+
poll_tables
|
47
|
+
@timers.every(Shoryuken::Later.poll_delay){ poll_tables }
|
48
|
+
|
49
|
+
# Loop watching for signals and firing off of timers
|
50
|
+
loop do
|
51
|
+
interval = @timers.wait_interval
|
52
|
+
readable, writable = IO.select([self_read], nil, nil, interval)
|
53
|
+
if readable
|
54
|
+
handle_signal readable.first.gets.strip
|
55
|
+
else
|
56
|
+
@timers.fire
|
57
|
+
end
|
48
58
|
end
|
49
59
|
rescue Interrupt
|
50
|
-
|
60
|
+
@timers.cancel
|
51
61
|
exit 0
|
52
62
|
end
|
53
63
|
end
|
64
|
+
|
65
|
+
protected
|
66
|
+
|
67
|
+
def poll_tables
|
68
|
+
logger.debug "Polling schedule tables"
|
69
|
+
@pollers.each do |poller|
|
70
|
+
poller.poll
|
71
|
+
end
|
72
|
+
logger.debug "Polling done"
|
73
|
+
end
|
54
74
|
|
55
75
|
private
|
56
76
|
|
57
|
-
def load_celluloid
|
58
|
-
raise "Celluloid cannot be required until here, or it will break Shoryuken::Later's daemonization" if defined?(::Celluloid) && Shoryuken::Later.options[:daemon]
|
59
|
-
|
60
|
-
# Celluloid can't be loaded until after we've daemonized
|
61
|
-
# because it spins up threads and creates locks which get
|
62
|
-
# into a very bad state if forked.
|
63
|
-
require 'celluloid/autostart'
|
64
|
-
Celluloid.logger = (Shoryuken::Later.options[:verbose] ? Shoryuken::Later.logger : nil)
|
65
|
-
|
66
|
-
require 'shoryuken/later/manager'
|
67
|
-
end
|
68
|
-
|
69
77
|
def load_rails
|
70
78
|
# Adapted from: https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/cli.rb
|
71
79
|
|
@@ -182,28 +190,11 @@ module Shoryuken
|
|
182
190
|
case sig
|
183
191
|
when 'USR1'
|
184
192
|
logger.info "Received USR1, will soft shutdown down"
|
185
|
-
|
186
|
-
|
187
|
-
|
193
|
+
@timers.cancel
|
194
|
+
sleep 1 while @busy
|
188
195
|
exit 0
|
189
|
-
when 'TTIN'
|
190
|
-
Thread.list.each do |thread|
|
191
|
-
logger.info "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}"
|
192
|
-
if thread.backtrace
|
193
|
-
logger.info thread.backtrace.join("\n")
|
194
|
-
else
|
195
|
-
logger.info "<no backtrace available>"
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
idle = launcher.manager.instance_variable_get(:@idle).size
|
200
|
-
busy = launcher.manager.instance_variable_get(:@busy).size
|
201
|
-
tables = launcher.manager.instance_variable_get(:@tables)
|
202
|
-
|
203
|
-
logger.info "Idle: #{idle}, Busy: #{busy}, Polled Tables: #{tables.join(', ')}"
|
204
196
|
else
|
205
197
|
logger.info "Received #{sig}, will shutdown down"
|
206
|
-
|
207
198
|
raise Interrupt
|
208
199
|
end
|
209
200
|
end
|
@@ -3,16 +3,12 @@ require 'json'
|
|
3
3
|
module Shoryuken
|
4
4
|
module Later
|
5
5
|
class Poller
|
6
|
-
include Celluloid
|
7
6
|
include Shoryuken::Util
|
8
7
|
|
9
8
|
attr_reader :table_name
|
10
9
|
|
11
|
-
def initialize(
|
12
|
-
@manager = manager
|
10
|
+
def initialize(table_name)
|
13
11
|
@table_name = table_name
|
14
|
-
|
15
|
-
@manager.async.poller_ready(@table_name, self)
|
16
12
|
end
|
17
13
|
|
18
14
|
def poll
|
@@ -25,12 +21,10 @@ module Shoryuken
|
|
25
21
|
while item = next_item
|
26
22
|
id = item.attributes['id']
|
27
23
|
logger.info "Found message #{id} from '#{@table_name}'"
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
logger.debug { "Skipping already queued message #{id} from '#{@table_name}'" }
|
33
|
-
end
|
24
|
+
if sent_msg = process_item(item)
|
25
|
+
logger.debug { "Enqueued message #{id} from '#{@table_name}' as #{sent_msg.id}" }
|
26
|
+
else
|
27
|
+
logger.debug { "Skipping already queued message #{id} from '#{@table_name}'" }
|
34
28
|
end
|
35
29
|
end
|
36
30
|
|
@@ -39,8 +33,6 @@ module Shoryuken
|
|
39
33
|
logger.error "Error fetching message: #{ex}"
|
40
34
|
logger.error ex.backtrace.first
|
41
35
|
end
|
42
|
-
|
43
|
-
@manager.async.poller_done(@table_name, self)
|
44
36
|
end
|
45
37
|
end
|
46
38
|
|
data/shoryuken-later.gemspec
CHANGED
@@ -28,6 +28,6 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_development_dependency "pry-byebug"
|
29
29
|
|
30
30
|
spec.add_dependency "aws-sdk-v1"
|
31
|
-
spec.add_dependency "
|
31
|
+
spec.add_dependency "timers", "~> 4.0.1"
|
32
32
|
spec.add_dependency "shoryuken", "~> 0.0.5"
|
33
33
|
end
|
@@ -1,9 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'shoryuken/later/poller'
|
3
|
-
require 'shoryuken/later/manager'
|
4
3
|
|
5
4
|
describe Shoryuken::Later::Poller do
|
6
|
-
let(:manager) { double Shoryuken::Later::Manager, poller_ready: nil, poller_done: nil }
|
7
5
|
let(:ddb_table) { double 'DynamoDb Table' }
|
8
6
|
let(:ddb_items) { double 'Table Items' }
|
9
7
|
let(:table) { 'shoryuken_later' }
|
@@ -17,38 +15,26 @@ describe Shoryuken::Later::Poller do
|
|
17
15
|
end
|
18
16
|
|
19
17
|
before do
|
20
|
-
allow(manager).to receive(:async).and_return(manager)
|
21
18
|
allow(Shoryuken::Later::Client).to receive(:tables).with(table).and_return(ddb_table)
|
22
19
|
end
|
23
20
|
|
24
21
|
subject do
|
25
|
-
described_class.new(
|
22
|
+
described_class.new(table)
|
26
23
|
end
|
27
24
|
|
28
|
-
describe '#initialize' do
|
29
|
-
it 'informs the manager that the poller is ready' do
|
30
|
-
expect(manager).to receive(:poller_ready).once
|
31
|
-
|
32
|
-
subject.inspect
|
33
|
-
subject.inspect
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
25
|
describe '#poll' do
|
38
26
|
it 'pulls items from #next_item, and processes with #process_item' do
|
39
27
|
items = [ddb_item]
|
40
28
|
expect_any_instance_of(described_class).to receive(:next_item).twice { items.pop }
|
41
29
|
expect_any_instance_of(described_class).to receive(:process_item).once.with(ddb_item)
|
42
|
-
expect(manager).to receive(:poller_done).once
|
43
30
|
|
44
31
|
subject.poll
|
45
32
|
end
|
46
33
|
|
47
|
-
it '
|
34
|
+
it 'does not call #process_item when there are no items' do
|
48
35
|
items = []
|
49
36
|
expect_any_instance_of(described_class).to receive(:next_item).once { items.pop }
|
50
37
|
expect_any_instance_of(described_class).not_to receive(:process_item)
|
51
|
-
expect(manager).to receive(:poller_done).once
|
52
38
|
|
53
39
|
subject.poll
|
54
40
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'bundler/setup'
|
2
2
|
Bundler.setup
|
3
3
|
|
4
|
-
require 'celluloid'
|
5
4
|
require 'shoryuken-later'
|
6
5
|
require 'json'
|
7
6
|
|
@@ -16,7 +15,6 @@ if File.exists? options_file
|
|
16
15
|
end
|
17
16
|
|
18
17
|
Shoryuken.logger.level = Logger::UNKNOWN
|
19
|
-
Celluloid.logger.level = Logger::UNKNOWN
|
20
18
|
|
21
19
|
# For Ruby 1.9
|
22
20
|
module Kernel
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shoryuken-later
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Khoobyar
|
@@ -87,19 +87,19 @@ dependencies:
|
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '0'
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
|
-
name:
|
90
|
+
name: timers
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
92
92
|
requirements:
|
93
93
|
- - ~>
|
94
94
|
- !ruby/object:Gem::Version
|
95
|
-
version: 0.
|
95
|
+
version: 4.0.1
|
96
96
|
type: :runtime
|
97
97
|
prerelease: false
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
99
99
|
requirements:
|
100
100
|
- - ~>
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: 0.
|
102
|
+
version: 4.0.1
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
104
|
name: shoryuken
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,8 +134,6 @@ files:
|
|
134
134
|
- lib/shoryuken/later/active_job_adapter.rb
|
135
135
|
- lib/shoryuken/later/cli.rb
|
136
136
|
- lib/shoryuken/later/client.rb
|
137
|
-
- lib/shoryuken/later/launcher.rb
|
138
|
-
- lib/shoryuken/later/manager.rb
|
139
137
|
- lib/shoryuken/later/poller.rb
|
140
138
|
- lib/shoryuken/later/version.rb
|
141
139
|
- lib/shoryuken/later/worker.rb
|
@@ -1,44 +0,0 @@
|
|
1
|
-
# All of this has been "borrowed" from Shoryuken.
|
2
|
-
|
3
|
-
# @see Shoryuken::Launcher
|
4
|
-
module Shoryuken
|
5
|
-
module Later
|
6
|
-
class Launcher
|
7
|
-
include Celluloid
|
8
|
-
include Shoryuken::Util
|
9
|
-
|
10
|
-
trap_exit :actor_died
|
11
|
-
|
12
|
-
attr_accessor :manager
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
@condvar = Celluloid::Condition.new
|
16
|
-
@manager = Shoryuken::Later::Manager.new_link(@condvar)
|
17
|
-
|
18
|
-
@done = false
|
19
|
-
end
|
20
|
-
|
21
|
-
def stop(options = {})
|
22
|
-
watchdog('Later::Launcher#stop') do
|
23
|
-
@done = true
|
24
|
-
|
25
|
-
manager.async.stop(shutdown: !!options[:shutdown], timeout: Shoryuken::Later.options[:timeout])
|
26
|
-
@condvar.wait
|
27
|
-
manager.terminate
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def run
|
32
|
-
watchdog('Later::Launcher#run') do
|
33
|
-
manager.async.start
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def actor_died(actor, reason)
|
38
|
-
return if @done
|
39
|
-
logger.warn 'Shoryuken::Later died due to the following error, cannot recover, process exiting'
|
40
|
-
exit 1
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,139 +0,0 @@
|
|
1
|
-
# Most of this has been "borrowed" from Shoryuken, but then repurposed for periodic polling.
|
2
|
-
|
3
|
-
# @see Shoryuken::Manager
|
4
|
-
require 'set'
|
5
|
-
require 'shoryuken/later/poller'
|
6
|
-
|
7
|
-
module Shoryuken
|
8
|
-
module Later
|
9
|
-
class Manager
|
10
|
-
include Celluloid
|
11
|
-
include Shoryuken::Util
|
12
|
-
|
13
|
-
def initialize(condvar)
|
14
|
-
@tables = Shoryuken::Later.tables.dup.uniq
|
15
|
-
@finished = condvar
|
16
|
-
|
17
|
-
@done = false
|
18
|
-
|
19
|
-
@idle = Set.new([])
|
20
|
-
@busy = Set.new([])
|
21
|
-
@timers = {}
|
22
|
-
|
23
|
-
@tables.each{|table| Poller.supervise_as :"poller-#{table}", current_actor, table }
|
24
|
-
end
|
25
|
-
|
26
|
-
def start
|
27
|
-
logger.info 'Starting'
|
28
|
-
|
29
|
-
# Start a poller for every table being polled.
|
30
|
-
@tables.each do |table|
|
31
|
-
dispatch table
|
32
|
-
|
33
|
-
# Save the timer so it can be cancelled at shutdown.
|
34
|
-
@timers[table] = every(Shoryuken::Later.poll_delay) { dispatch table }
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def stop(options = {})
|
39
|
-
watchdog('Later::Manager#stop died') do
|
40
|
-
@done = true
|
41
|
-
|
42
|
-
@timers.each_value{|timer| timer.cancel if timer }
|
43
|
-
@timers.clear
|
44
|
-
|
45
|
-
logger.info { "Shutting down #{@idle.size} idle poller(s)" }
|
46
|
-
|
47
|
-
@idle.each do |name|
|
48
|
-
poller = Actor[name] and poller.alive? and poller.terminate
|
49
|
-
end
|
50
|
-
@idle.clear
|
51
|
-
|
52
|
-
if @busy.empty?
|
53
|
-
return after(0) { @finished.signal }
|
54
|
-
end
|
55
|
-
|
56
|
-
if options[:shutdown]
|
57
|
-
hard_shutdown_in(options[:timeout])
|
58
|
-
else
|
59
|
-
soft_shutdown(options[:timeout])
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def poller_done(table, poller)
|
65
|
-
watchdog('Later::Manager#poller_done died') do
|
66
|
-
logger.debug { "Poller done for '#{table}'" }
|
67
|
-
|
68
|
-
name = :"poller-#{table}"
|
69
|
-
@busy.delete name
|
70
|
-
|
71
|
-
if stopped?
|
72
|
-
poller.terminate if poller.alive?
|
73
|
-
else
|
74
|
-
@idle << name
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def poller_ready(table, poller)
|
80
|
-
watchdog('Later::Manager#poller_ready died') do
|
81
|
-
logger.debug { "Poller for '#{table}' ready" }
|
82
|
-
|
83
|
-
name = :"poller-#{table}"
|
84
|
-
@busy.delete name
|
85
|
-
@idle << name
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def stopped?
|
90
|
-
@done
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
def dispatch(table)
|
96
|
-
name = :"poller-#{table}"
|
97
|
-
|
98
|
-
# Only start polling if the poller is idle.
|
99
|
-
if ! stopped? && @idle.include?(name)
|
100
|
-
@idle.delete(name)
|
101
|
-
@busy << name
|
102
|
-
|
103
|
-
Actor[name].async.poll
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def soft_shutdown(delay)
|
108
|
-
logger.info { "Waiting for #{@busy.size} busy pollers" }
|
109
|
-
|
110
|
-
if @busy.size > 0
|
111
|
-
after(delay) { soft_shutdown(delay) }
|
112
|
-
else
|
113
|
-
@finished.signal
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def hard_shutdown_in(delay)
|
118
|
-
logger.info { "Waiting for #{@busy.size} busy pollers" }
|
119
|
-
logger.info { "Pausing up to #{delay} seconds to allow pollers to finish..." }
|
120
|
-
|
121
|
-
after(delay) do
|
122
|
-
watchdog("Later::Manager#hard_shutdown_in died") do
|
123
|
-
if @busy.size > 0
|
124
|
-
logger.info { "Hard shutting down #{@busy.size} busy pollers" }
|
125
|
-
|
126
|
-
@busy.each do |busy|
|
127
|
-
if poller = Actor[busy]
|
128
|
-
t = poller.bare_object.actual_work_thread
|
129
|
-
t.raise Shutdown if poller.alive?
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
@finished.signal
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|