asir 1.0.8 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +8 -0
- data/README.textile +4 -8
- data/asir.gemspec +0 -1
- data/example/asir_control.sh +0 -23
- data/example/config/asir_config.rb +0 -5
- data/example/ex26.rb +24 -0
- data/example/example_helper.rb +1 -0
- data/lib/asir/thread_pool.rb +218 -0
- data/lib/asir/transport/connection_oriented.rb +4 -4
- data/lib/asir/transport/file.rb +2 -2
- data/lib/asir/transport/payload_io.rb +2 -2
- data/lib/asir/transport/resque.rb +5 -5
- data/lib/asir/transport/thread.rb +41 -0
- data/lib/asir/version.rb +1 -1
- data/spec/thread_pool_spec.rb +57 -0
- metadata +9 -24
- data/example/asir_control_client_zmq.rb +0 -15
- data/example/ex20.rb +0 -28
- data/example/ex21.rb +0 -28
- data/lib/asir/transport/zmq.rb +0 -107
data/ChangeLog
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
2012-12-03 Kurt A. Stephens <ks.github@kurtstephens.com>
|
2
|
+
|
3
|
+
* v1.1.0: New version.
|
4
|
+
* ZMQ: Moved ZMQ support to gem asir_zmq.
|
5
|
+
* Thread: Preliminary ASIR::Transport::Thread.
|
6
|
+
* ThreadPool: Preliminary ASIR::ThreadPool suitable for Thread transport.
|
7
|
+
* Resque: Support for message[:resque_queue] || message[:queue].
|
8
|
+
|
1
9
|
2012-11-30 Kurt A. Stephens <ks.github@kurtstephens.com>
|
2
10
|
|
3
11
|
* v1.0.8: New version.
|
data/README.textile
CHANGED
@@ -26,12 +26,13 @@ h3. Features
|
|
26
26
|
** Named Pipe.
|
27
27
|
** TCP.
|
28
28
|
** HTTP under WEBrick or as Rack application.
|
29
|
-
** Beanstalkd.
|
30
|
-
** ZeroMQ.
|
31
|
-
** Resque.
|
29
|
+
** Beanstalkd. (gem asir_beanstalk)
|
30
|
+
** ZeroMQ. (gem asir_zmq)
|
31
|
+
** Resque. (gem asir_resque)
|
32
32
|
** Buffered transports.
|
33
33
|
** Broadcast transports.
|
34
34
|
** Fallback transports.
|
35
|
+
** Database transports (e.g.: gem asir_activerecord)
|
35
36
|
** Time-decaying retry and polling logic.
|
36
37
|
* Support for multiple encodings:
|
37
38
|
** Marshal.
|
@@ -50,9 +51,4 @@ h2. Platform support
|
|
50
51
|
* CRuby 2.0-head
|
51
52
|
* JRuby 1.6.x (with JRUBY_OPTS=--1.9) IN-PROGRESS
|
52
53
|
|
53
|
-
h2. Dependencies
|
54
|
-
|
55
|
-
* gem install zmq
|
56
|
-
** zmq 2.1.4 needs a zmq 2.x library.
|
57
|
-
** On OS X Macports: sudo port install zmq22.
|
58
54
|
|
data/asir.gemspec
CHANGED
@@ -31,7 +31,6 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.add_dependency "httpclient", "~> 2.3.0"
|
32
32
|
s.add_dependency "libxml-ruby", "~> 2.3.3"
|
33
33
|
s.add_dependency "rack", "~> 1.4.1"
|
34
|
-
s.add_dependency "zmq", "~> 2.1.4"
|
35
34
|
s.add_dependency "json", ">= 1.5.3"
|
36
35
|
|
37
36
|
s.add_development_dependency 'rake', '>= 0.9.0'
|
data/example/asir_control.sh
CHANGED
@@ -33,29 +33,6 @@ esac
|
|
33
33
|
|
34
34
|
#############################
|
35
35
|
|
36
|
-
case "$args"
|
37
|
-
in
|
38
|
-
*zmq*|*ALL*)
|
39
|
-
|
40
|
-
$asir start zmq worker
|
41
|
-
sleep 1
|
42
|
-
$asir pid zmq worker
|
43
|
-
if $asir alive zmq worker; then
|
44
|
-
echo "alive"
|
45
|
-
fi
|
46
|
-
|
47
|
-
ruby "$dir/asir_control_client_zmq.rb"
|
48
|
-
sleep 1
|
49
|
-
|
50
|
-
$asir stop zmq worker
|
51
|
-
sleep 1
|
52
|
-
$asir pid zmq worker
|
53
|
-
|
54
|
-
;;
|
55
|
-
esac
|
56
|
-
|
57
|
-
#############################
|
58
|
-
|
59
36
|
case "$args"
|
60
37
|
in
|
61
38
|
*resque*|*ALL*)
|
@@ -47,11 +47,6 @@ when :transport
|
|
47
47
|
require 'asir/transport/rack'
|
48
48
|
transport = ASIR::Transport::Rack.new
|
49
49
|
transport.uri = "http://localhost:#{30000 + asir.identifier.to_s.to_i}/asir"
|
50
|
-
when :zmq
|
51
|
-
reqiore 'asir/transport/zmq'
|
52
|
-
transport = ASIR::Transport::Zmq.new
|
53
|
-
transport.one_way = true
|
54
|
-
transport.uri = "tcp://localhost:#{31000 + asir.identifier.to_s.to_i}" # /asir"
|
55
50
|
when :resque
|
56
51
|
gem 'resque'
|
57
52
|
require 'asir/transport/resque'
|
data/example/ex26.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#
|
2
|
+
# !SLIDE :capture_code_output true
|
3
|
+
# One-way, asynchronous thread service
|
4
|
+
|
5
|
+
require 'example_helper'
|
6
|
+
begin
|
7
|
+
Email.asir.transport = t =
|
8
|
+
ASIR::Transport::Thread.new
|
9
|
+
|
10
|
+
t.after_thread_new = lambda do | transport, message, thread |
|
11
|
+
$stderr.puts "\n #{$$}: Spawned Thread #{thread.inspect}"
|
12
|
+
end
|
13
|
+
|
14
|
+
pr Email.asir.send_email(:pdf_invoice,
|
15
|
+
:to => "user@email.com",
|
16
|
+
:customer => @customer)
|
17
|
+
end
|
18
|
+
|
19
|
+
# !SLIDE END
|
20
|
+
# EXPECT: : Spawned Thread
|
21
|
+
# EXPECT: : client process
|
22
|
+
# EXPECT: : Email.send_mail :pdf_invoice
|
23
|
+
# EXPECT: : pr: nil
|
24
|
+
|
data/example/example_helper.rb
CHANGED
@@ -11,6 +11,7 @@ require 'asir'
|
|
11
11
|
require 'asir/transport/file'
|
12
12
|
require 'asir/transport/local'
|
13
13
|
require 'asir/transport/subprocess'
|
14
|
+
require 'asir/transport/thread'
|
14
15
|
require 'asir/transport/tcp_socket'
|
15
16
|
require 'asir/transport/fallback'
|
16
17
|
require 'asir/transport/broadcast'
|
@@ -0,0 +1,218 @@
|
|
1
|
+
require 'asir/initialization'
|
2
|
+
require 'asir/additional_data'
|
3
|
+
require 'thread'
|
4
|
+
require "time"
|
5
|
+
|
6
|
+
module ASIR
|
7
|
+
class ThreadPool
|
8
|
+
include Initialization, AdditionalData
|
9
|
+
attr_accessor :thread_class, :workers, :n_workers
|
10
|
+
attr_accessor :work_queue
|
11
|
+
attr_accessor :verbose
|
12
|
+
attr_accessor :run
|
13
|
+
|
14
|
+
def initialize *args
|
15
|
+
super
|
16
|
+
@thread_class ||= ::Thread
|
17
|
+
@workers_mutex = Mutex.new
|
18
|
+
@work_mutex = Mutex.new
|
19
|
+
@workers ||= [ ]
|
20
|
+
@work_queue ||= Queue.new
|
21
|
+
@run = false
|
22
|
+
@work_id = @worker_id = 0
|
23
|
+
@time_0 ||= Time.now
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns a new Work object.
|
27
|
+
def new &blk
|
28
|
+
work_id = @work_mutex.synchronize do
|
29
|
+
@work_id += 1
|
30
|
+
end
|
31
|
+
work = Work.new(:block => blk, :work_id => work_id)
|
32
|
+
work_created! work
|
33
|
+
@work_queue.enq(work)
|
34
|
+
@run = true
|
35
|
+
start_workers! if @auto_start_workers
|
36
|
+
work
|
37
|
+
end
|
38
|
+
|
39
|
+
# Keep a list of workers busy.
|
40
|
+
def start_workers!
|
41
|
+
return nil unless @run
|
42
|
+
workers_size = @workers.size
|
43
|
+
want_n = [ n_workers, @work_queue.size ].min
|
44
|
+
want_n = n_workers if want_n > n_workers
|
45
|
+
start_n = want_n - workers_size
|
46
|
+
start_n = 0 if start_n < 0
|
47
|
+
return unless start_n > 0
|
48
|
+
log! { "start_workers! #{start_n}" }
|
49
|
+
start_n.times do
|
50
|
+
thread_class.new do
|
51
|
+
worker_id = @workers_mutex.synchronize do
|
52
|
+
@worker_id += 1
|
53
|
+
end
|
54
|
+
worker = Worker.new(:thread_pool => self, :worker_id => worker_id)
|
55
|
+
worker_created! worker
|
56
|
+
begin
|
57
|
+
worker_starting! worker
|
58
|
+
@workers_mutex.synchronize do
|
59
|
+
@workers << worker
|
60
|
+
end
|
61
|
+
worker.run!
|
62
|
+
# rescue ::Exception => exc
|
63
|
+
# log! "ERROR: #{exc.inspect}\n#{exc.backtrace * "\n"}"
|
64
|
+
# raise exc
|
65
|
+
ensure
|
66
|
+
@workers_mutex.synchronize do
|
67
|
+
@workers.delete(worker)
|
68
|
+
end
|
69
|
+
worker_stopping! worker
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def worker_created! worker
|
77
|
+
log! { "worker_created! #{worker.inspect}" }
|
78
|
+
end
|
79
|
+
|
80
|
+
def worker_starting! worker
|
81
|
+
log! { "worker_starting! #{worker}" }
|
82
|
+
end
|
83
|
+
|
84
|
+
def worker_stopping! worker
|
85
|
+
log! { "worker_stopping! #{worker}" }
|
86
|
+
end
|
87
|
+
|
88
|
+
def work_created! work
|
89
|
+
log! { "work_created! #{work.inspect}" }
|
90
|
+
end
|
91
|
+
|
92
|
+
def work_starting! work
|
93
|
+
log! { "work_starting! #{work.inspect} #{work.worker.inspect}" }
|
94
|
+
end
|
95
|
+
|
96
|
+
def work_stopping! work
|
97
|
+
log! { "work_stopping! #{work.inspect}" }
|
98
|
+
end
|
99
|
+
|
100
|
+
def log! msg = nil
|
101
|
+
return unless @verbose
|
102
|
+
msg ||= yield
|
103
|
+
@time_1 = Time.now
|
104
|
+
$stderr.puts " #{@time_1 - @time_0} #{$$} #{Thread.current.object_id} #{self} #{msg}"
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
108
|
+
def stop!
|
109
|
+
log! "stop!"
|
110
|
+
@run = false
|
111
|
+
# Ask each current worker to :stop!
|
112
|
+
@workers_mutex.synchronize do
|
113
|
+
@workers.each do | w |
|
114
|
+
@work_queue.enq :stop!
|
115
|
+
end
|
116
|
+
end
|
117
|
+
# Just incase.
|
118
|
+
@work_queue.enq :stop!
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
def kill! *args
|
123
|
+
log! "kill!"
|
124
|
+
@run = false
|
125
|
+
@workers_mutex.synchronize do
|
126
|
+
@workers.each do | worker |
|
127
|
+
worker.kill! *args
|
128
|
+
end
|
129
|
+
end
|
130
|
+
self
|
131
|
+
end
|
132
|
+
|
133
|
+
def join *args
|
134
|
+
until @workers.empty?
|
135
|
+
@workers.each do | worker |
|
136
|
+
worker.join(*args)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class Work
|
142
|
+
include Initialization, AdditionalData
|
143
|
+
attr_accessor :work_id, :block, :thread, :worker
|
144
|
+
attr_accessor :started, :finished
|
145
|
+
|
146
|
+
def to_s; super.sub(/>$/, " #{@work_id}>"); end
|
147
|
+
def inspect; to_s; end
|
148
|
+
|
149
|
+
def run!
|
150
|
+
@thread = ::Thread.current
|
151
|
+
thread_pool.work_starting! self
|
152
|
+
@started = true
|
153
|
+
@block.call
|
154
|
+
@finished = true
|
155
|
+
ensure
|
156
|
+
@thread = nil
|
157
|
+
thread_pool.work_stopping! self
|
158
|
+
end
|
159
|
+
def thread_pool; @worker.thread_pool; end
|
160
|
+
end
|
161
|
+
|
162
|
+
class Worker
|
163
|
+
include Initialization, AdditionalData
|
164
|
+
attr_accessor :thread_pool, :worker_id
|
165
|
+
# Current Work and Thread.
|
166
|
+
attr_accessor :work, :thread
|
167
|
+
attr_accessor :run, :running, :stopping, :stopped
|
168
|
+
|
169
|
+
def to_s; super.sub(/>$/, " #{@worker_id} #{@work_inspect}>"); end
|
170
|
+
def inspect; to_s; end
|
171
|
+
|
172
|
+
def run!
|
173
|
+
@thread = Thread.current
|
174
|
+
@run = @running = true
|
175
|
+
while @run
|
176
|
+
work = thread_pool.work_queue.deq
|
177
|
+
if work == :stop!
|
178
|
+
@run = false
|
179
|
+
@stopping = true
|
180
|
+
break
|
181
|
+
end
|
182
|
+
begin
|
183
|
+
@work = work
|
184
|
+
work.worker = self
|
185
|
+
work.run!
|
186
|
+
ensure
|
187
|
+
work.thread = work.worker = nil
|
188
|
+
@work = nil
|
189
|
+
end
|
190
|
+
end
|
191
|
+
ensure
|
192
|
+
if @stopping
|
193
|
+
@stopped = true
|
194
|
+
end
|
195
|
+
@running = false
|
196
|
+
@thread = nil
|
197
|
+
end
|
198
|
+
|
199
|
+
def join *args
|
200
|
+
@run = false
|
201
|
+
@thread.join(*args) if @thread
|
202
|
+
end
|
203
|
+
|
204
|
+
def stop!
|
205
|
+
@stopping = true
|
206
|
+
@run = false
|
207
|
+
self
|
208
|
+
end
|
209
|
+
|
210
|
+
def kill! *args
|
211
|
+
stop!
|
212
|
+
@thread.raise(*args) if @thread
|
213
|
+
self
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
@@ -54,21 +54,21 @@ module ASIR
|
|
54
54
|
# Sends the encoded Message payload String.
|
55
55
|
def _send_message message, message_payload
|
56
56
|
stream.with_stream! do | io |
|
57
|
-
_write message_payload, io
|
57
|
+
_write message_payload, io, message
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
61
|
# !SLIDE
|
62
62
|
# Receives the encoded Message payload String.
|
63
63
|
def _receive_message stream, additional_data
|
64
|
-
[ _read(stream), nil ]
|
64
|
+
[ _read(stream, nil), nil ]
|
65
65
|
end
|
66
66
|
|
67
67
|
# !SLIDE
|
68
68
|
# Sends the encoded Result payload String.
|
69
69
|
def _send_result message, result, result_payload, stream, message_state
|
70
70
|
unless @one_way || message.one_way
|
71
|
-
_write result_payload, stream
|
71
|
+
_write result_payload, stream, message
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -77,7 +77,7 @@ module ASIR
|
|
77
77
|
def _receive_result message, opaque_result
|
78
78
|
unless @one_way || message.one_way
|
79
79
|
stream.with_stream! do | io |
|
80
|
-
_read io
|
80
|
+
_read io, message
|
81
81
|
end
|
82
82
|
end
|
83
83
|
end
|
data/lib/asir/transport/file.rb
CHANGED
@@ -16,14 +16,14 @@ module ASIR
|
|
16
16
|
|
17
17
|
# Writes a Message payload String.
|
18
18
|
def _send_message message, message_payload
|
19
|
-
_write message_payload, stream
|
19
|
+
_write message_payload, stream, message
|
20
20
|
ensure
|
21
21
|
close if file && ::File.pipe?(file)
|
22
22
|
end
|
23
23
|
|
24
24
|
# Returns a Message payload String.
|
25
25
|
def _receive_message stream, additional_data
|
26
|
-
[ _read(stream), nil ]
|
26
|
+
[ _read(stream, nil), nil ]
|
27
27
|
end
|
28
28
|
|
29
29
|
# one-way; no Result.
|
@@ -14,7 +14,7 @@ module ASIR
|
|
14
14
|
HEADER = "# asir_payload_size: "
|
15
15
|
FOOTER = "\n# asir_payload_end"
|
16
16
|
|
17
|
-
def _write payload, stream
|
17
|
+
def _write payload, stream, context
|
18
18
|
stream.write HEADER
|
19
19
|
stream.puts payload.size
|
20
20
|
stream.write payload
|
@@ -23,7 +23,7 @@ module ASIR
|
|
23
23
|
stream
|
24
24
|
end
|
25
25
|
|
26
|
-
def _read stream
|
26
|
+
def _read stream, context
|
27
27
|
size = /\d+$/.match(stream.readline.chomp)[0].to_i # HEADER (size)
|
28
28
|
payload = stream.read(size)
|
29
29
|
stream.readline # FOOTER
|
@@ -49,7 +49,7 @@ module ASIR
|
|
49
49
|
|
50
50
|
def _send_message message, message_payload
|
51
51
|
stream.with_stream! do | io | # Force connect
|
52
|
-
queue = message[:resque_queue] || self.queue
|
52
|
+
queue = message[:resque_queue] || message[:queue] || self.queue
|
53
53
|
$stderr.puts " #{$$} #{self} _send_message #{message_payload.inspect} to queue=#{queue.inspect} as #{self.class} :process_job" if @verbose >= 2
|
54
54
|
# Invokes Transport::Resque.perform(metadata, payload)
|
55
55
|
metadata = message[:resque_metadata] || message.description
|
@@ -104,8 +104,8 @@ module ASIR
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def serve_stream_message! in_stream, out_stream # ignored
|
107
|
-
save = Thread.current[:asir_transport_resque_instance]
|
108
|
-
Thread.current[:asir_transport_resque_instance] = self
|
107
|
+
save = ::Thread.current[:asir_transport_resque_instance]
|
108
|
+
::Thread.current[:asir_transport_resque_instance] = self
|
109
109
|
poll_throttle throttle do
|
110
110
|
$stderr.puts " #{$$} #{self} serve_stream_message!: resque_worker = #{resque_worker} on queues #{resque_worker.queues.inspect}" if @verbose >= 3
|
111
111
|
if job = resque_worker.reserve
|
@@ -116,14 +116,14 @@ module ASIR
|
|
116
116
|
end
|
117
117
|
self
|
118
118
|
ensure
|
119
|
-
Thread.current[:asir_transport_resque_instance] = save
|
119
|
+
::Thread.current[:asir_transport_resque_instance] = save
|
120
120
|
end
|
121
121
|
|
122
122
|
# Class method entry point from Resque::Job.perform.
|
123
123
|
def self.perform metadata, payload = nil
|
124
124
|
payload ||= metadata # old calling signature (just payload).
|
125
125
|
# $stderr.puts " #{self} process_job payload=#{payload.inspect}"
|
126
|
-
t = Thread.current[:asir_transport_resque_instance]
|
126
|
+
t = ::Thread.current[:asir_transport_resque_instance]
|
127
127
|
# Pass payload as in_stream; _receive_message will return it.
|
128
128
|
t.serve_message! payload, nil
|
129
129
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'asir/transport/local'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module ASIR
|
5
|
+
class Transport
|
6
|
+
# !SLIDE
|
7
|
+
# Thread Transport
|
8
|
+
#
|
9
|
+
# Send one-way Message to a Thread.
|
10
|
+
class Thread < Local
|
11
|
+
# Any object that responds to .new(&blk).
|
12
|
+
# Defaults to ::Thread.
|
13
|
+
attr_accessor :thread_class
|
14
|
+
|
15
|
+
# Callback: call(self, message, thr).
|
16
|
+
attr_accessor :after_thread_new
|
17
|
+
|
18
|
+
def initialize *args
|
19
|
+
@thread_class = ::Thread
|
20
|
+
@one_way = true; super
|
21
|
+
end
|
22
|
+
|
23
|
+
def _send_message message, message_payload
|
24
|
+
thr = thread_class.new do
|
25
|
+
send_result(super, nil, nil)
|
26
|
+
end
|
27
|
+
@after_thread_new.call(self, message, thr) if @after_thread_new
|
28
|
+
thr
|
29
|
+
end
|
30
|
+
|
31
|
+
# one-way; no Result
|
32
|
+
def _receive_result message, opaque_result
|
33
|
+
end
|
34
|
+
|
35
|
+
# one-way; no Result
|
36
|
+
def _send_result message, result, result_payload, stream, message_state
|
37
|
+
end
|
38
|
+
end
|
39
|
+
# !SLIDE END
|
40
|
+
end
|
41
|
+
end
|
data/lib/asir/version.rb
CHANGED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'asir/thread_pool'
|
2
|
+
|
3
|
+
describe 'ASIR::ThreadPool' do
|
4
|
+
it "should spawn workers only as needed" do
|
5
|
+
tp.workers.size.should == 0
|
6
|
+
work = tp.new do
|
7
|
+
$stderr.puts "#{Thread.current} start" if @verbose
|
8
|
+
sleep 2
|
9
|
+
$stderr.puts "#{Thread.current} stop" if @verbose
|
10
|
+
end
|
11
|
+
tp.workers.size.should == 0
|
12
|
+
work.class.should == ASIR::ThreadPool::Work
|
13
|
+
tp.start_workers!
|
14
|
+
sleep 0.25
|
15
|
+
tp.workers.size.should == 1
|
16
|
+
worker = tp.workers.first
|
17
|
+
worker.class.should == ASIR::ThreadPool::Worker
|
18
|
+
worker.work.should == work
|
19
|
+
work.worker.should == worker
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should spawn up to n_workers only" do
|
23
|
+
# tp.verbose = 1
|
24
|
+
works = [ ]
|
25
|
+
20.times do
|
26
|
+
works << tp.new do
|
27
|
+
$stderr.puts "#{Thread.current} start" if @verbose
|
28
|
+
sleep 0.2
|
29
|
+
$stderr.puts "#{Thread.current} stop" if @verbose
|
30
|
+
end
|
31
|
+
end
|
32
|
+
tp.start_workers!
|
33
|
+
sleep 0.25
|
34
|
+
tp.workers.size.should == n_workers
|
35
|
+
tp.stop!
|
36
|
+
tp.join
|
37
|
+
tp.workers.size.should == 0
|
38
|
+
works.each do | work |
|
39
|
+
work.started.should == true
|
40
|
+
work.finished.should == true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def n_workers
|
45
|
+
@n_workers ||= 10
|
46
|
+
end
|
47
|
+
|
48
|
+
def tp
|
49
|
+
@tp ||= ASIR::ThreadPool.new(:n_workers => n_workers)
|
50
|
+
end
|
51
|
+
|
52
|
+
after :each do
|
53
|
+
if @tp
|
54
|
+
@tp.kill! rescue nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asir
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: uuid
|
@@ -107,22 +107,6 @@ dependencies:
|
|
107
107
|
- - ~>
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: 1.4.1
|
110
|
-
- !ruby/object:Gem::Dependency
|
111
|
-
name: zmq
|
112
|
-
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
|
-
requirements:
|
115
|
-
- - ~>
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: 2.1.4
|
118
|
-
type: :runtime
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
|
-
requirements:
|
123
|
-
- - ~>
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
version: 2.1.4
|
126
110
|
- !ruby/object:Gem::Dependency
|
127
111
|
name: json
|
128
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -228,7 +212,6 @@ files:
|
|
228
212
|
- example/asir_control.sh
|
229
213
|
- example/asir_control_client_http.rb
|
230
214
|
- example/asir_control_client_resque.rb
|
231
|
-
- example/asir_control_client_zmq.rb
|
232
215
|
- example/config/asir_config.rb
|
233
216
|
- example/delayed_service.rb
|
234
217
|
- example/ex01.rb
|
@@ -250,12 +233,11 @@ files:
|
|
250
233
|
- example/ex17.rb
|
251
234
|
- example/ex18.rb
|
252
235
|
- example/ex19.rb
|
253
|
-
- example/ex20.rb
|
254
|
-
- example/ex21.rb
|
255
236
|
- example/ex22.rb
|
256
237
|
- example/ex23.rb
|
257
238
|
- example/ex24.rb
|
258
239
|
- example/ex25.rb
|
240
|
+
- example/ex26.rb
|
259
241
|
- example/example_helper.rb
|
260
242
|
- example/sample_service.rb
|
261
243
|
- example/unsafe_service.rb
|
@@ -312,6 +294,7 @@ files:
|
|
312
294
|
- lib/asir/poll_throttle.rb
|
313
295
|
- lib/asir/result.rb
|
314
296
|
- lib/asir/retry_behavior.rb
|
297
|
+
- lib/asir/thread_pool.rb
|
315
298
|
- lib/asir/thread_variable.rb
|
316
299
|
- lib/asir/transport.rb
|
317
300
|
- lib/asir/transport/beanstalk.rb
|
@@ -336,8 +319,8 @@ files:
|
|
336
319
|
- lib/asir/transport/stream.rb
|
337
320
|
- lib/asir/transport/subprocess.rb
|
338
321
|
- lib/asir/transport/tcp_socket.rb
|
322
|
+
- lib/asir/transport/thread.rb
|
339
323
|
- lib/asir/transport/webrick.rb
|
340
|
-
- lib/asir/transport/zmq.rb
|
341
324
|
- lib/asir/uri_config.rb
|
342
325
|
- lib/asir/uuid.rb
|
343
326
|
- lib/asir/version.rb
|
@@ -350,6 +333,7 @@ files:
|
|
350
333
|
- spec/performance_spec.rb
|
351
334
|
- spec/resque_spec.rb
|
352
335
|
- spec/spec_helper.rb
|
336
|
+
- spec/thread_pool_spec.rb
|
353
337
|
- spec/thread_variable_spec.rb
|
354
338
|
- spec/transport_spec.rb
|
355
339
|
- spec/xml_spec.rb
|
@@ -369,7 +353,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
369
353
|
version: '0'
|
370
354
|
segments:
|
371
355
|
- 0
|
372
|
-
hash:
|
356
|
+
hash: 2626327431831346289
|
373
357
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
374
358
|
none: false
|
375
359
|
requirements:
|
@@ -378,7 +362,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
378
362
|
version: '0'
|
379
363
|
segments:
|
380
364
|
- 0
|
381
|
-
hash:
|
365
|
+
hash: 2626327431831346289
|
382
366
|
requirements: []
|
383
367
|
rubyforge_project:
|
384
368
|
rubygems_version: 1.8.24
|
@@ -395,6 +379,7 @@ test_files:
|
|
395
379
|
- spec/performance_spec.rb
|
396
380
|
- spec/resque_spec.rb
|
397
381
|
- spec/spec_helper.rb
|
382
|
+
- spec/thread_pool_spec.rb
|
398
383
|
- spec/thread_variable_spec.rb
|
399
384
|
- spec/transport_spec.rb
|
400
385
|
- spec/xml_spec.rb
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'example_helper'
|
2
|
-
require 'asir/transport/zmq'
|
3
|
-
require 'asir/coder/marshal'
|
4
|
-
begin
|
5
|
-
Email.asir.transport = t =
|
6
|
-
ASIR::Transport::Zmq.new(:uri => "tcp://localhost:31000") # "/asir"
|
7
|
-
t.one_way = true
|
8
|
-
t.encoder = ASIR::Coder::Marshal.new
|
9
|
-
pr Email.asir.send_email(:pdf_invoice,
|
10
|
-
:to => "user@email.com",
|
11
|
-
:customer => @customer)
|
12
|
-
ensure
|
13
|
-
t.close rescue nil
|
14
|
-
end
|
15
|
-
|
data/example/ex20.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# !SLIDE :capture_code_output true
|
2
|
-
# One-way ZMQ service.
|
3
|
-
|
4
|
-
require 'example_helper'
|
5
|
-
require 'asir/transport/zmq'
|
6
|
-
begin
|
7
|
-
zmq = ASIR::Transport::Zmq.new(:port => 31920,
|
8
|
-
:encoder => ASIR::Coder::Marshal.new,
|
9
|
-
:one_way => true)
|
10
|
-
server_process do
|
11
|
-
zmq.prepare_server!
|
12
|
-
zmq.run_server!
|
13
|
-
end
|
14
|
-
UnsafeService.asir.transport = t = zmq
|
15
|
-
pr UnsafeService.asir.do_it(":ok")
|
16
|
-
rescue ::Exception => err
|
17
|
-
$stderr.puts "### #{$$}: ERROR: #{err.inspect}\n #{err.backtrace * "\n "}"
|
18
|
-
raise
|
19
|
-
ensure
|
20
|
-
zmq.close rescue nil; sleep 1; server_kill
|
21
|
-
end
|
22
|
-
|
23
|
-
# !SLIDE END
|
24
|
-
# EXPECT: : client process
|
25
|
-
# EXPECT: : server process
|
26
|
-
# EXPECT: UnsafeService.do_it => :ok
|
27
|
-
# EXPECT: : pr: nil
|
28
|
-
# EXPECT!: ERROR
|
data/example/ex21.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# !SLIDE :capture_code_output true
|
2
|
-
# Bi-directional ZMQ service.
|
3
|
-
|
4
|
-
require 'example_helper'
|
5
|
-
require 'asir/transport/zmq'
|
6
|
-
begin
|
7
|
-
zmq = ASIR::Transport::Zmq.new(:port => 31920,
|
8
|
-
:encoder => ASIR::Coder::Marshal.new,
|
9
|
-
:one_way => false)
|
10
|
-
server_process do
|
11
|
-
zmq.prepare_server!
|
12
|
-
zmq.run_server!
|
13
|
-
end
|
14
|
-
UnsafeService.asir.transport = t = zmq
|
15
|
-
pr UnsafeService.asir.do_it(":ok")
|
16
|
-
rescue ::Exception => err
|
17
|
-
$stderr.puts "### #{$$}: ERROR: #{err.inspect}\n #{err.backtrace * "\n "}"
|
18
|
-
raise
|
19
|
-
ensure
|
20
|
-
zmq.close rescue nil; sleep 1; server_kill
|
21
|
-
end
|
22
|
-
|
23
|
-
# !SLIDE END
|
24
|
-
# EXPECT: : client process
|
25
|
-
# EXPECT: : server process
|
26
|
-
# EXPECT: UnsafeService.do_it => :ok
|
27
|
-
# EXPECT: : pr: :ok
|
28
|
-
# EXPECT!: ERROR
|
data/lib/asir/transport/zmq.rb
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
require 'asir/transport/connection_oriented'
|
2
|
-
gem 'zmq'
|
3
|
-
require 'zmq'
|
4
|
-
|
5
|
-
module ASIR
|
6
|
-
class Transport
|
7
|
-
# !SLIDE
|
8
|
-
# ZeroMQ Transport
|
9
|
-
class Zmq < ConnectionOriented
|
10
|
-
attr_accessor :queue
|
11
|
-
|
12
|
-
# !SLIDE
|
13
|
-
# 0MQ client.
|
14
|
-
def _client_connect!
|
15
|
-
sock = zmq_context.socket(one_way ? ZMQ::PUB : ZMQ::REQ)
|
16
|
-
sock.connect(zmq_uri)
|
17
|
-
sock
|
18
|
-
rescue ::Exception => exc
|
19
|
-
raise exc.class, "#{self.class} #{zmq_uri}: #{exc.message}", exc.backtrace
|
20
|
-
end
|
21
|
-
|
22
|
-
# !SLIDE
|
23
|
-
# 0MQ server.
|
24
|
-
def _server!
|
25
|
-
sock = zmq_context.socket(one_way ? ZMQ::SUB : ZMQ::REP)
|
26
|
-
sock.setsockopt(ZMQ::SUBSCRIBE, queue) if one_way
|
27
|
-
sock.bind("tcp://*:#{port}") # WTF?: why doesn't tcp://localhost:PORT work?
|
28
|
-
@server = sock
|
29
|
-
rescue ::Exception => exc
|
30
|
-
raise exc.class, "#{self.class} #{zmq_uri}: #{exc.message}", exc.backtrace
|
31
|
-
end
|
32
|
-
|
33
|
-
def _receive_result message, opaque_result
|
34
|
-
return nil if one_way || message.one_way
|
35
|
-
super
|
36
|
-
end
|
37
|
-
|
38
|
-
def _send_result message, result, result_payload, stream, message_state
|
39
|
-
return nil if one_way || message.one_way
|
40
|
-
super
|
41
|
-
end
|
42
|
-
|
43
|
-
def _write payload, stream
|
44
|
-
payload.insert(0, queue_) if one_way
|
45
|
-
stream.send payload, 0
|
46
|
-
stream
|
47
|
-
end
|
48
|
-
|
49
|
-
def _read stream
|
50
|
-
stream.recv 0
|
51
|
-
end
|
52
|
-
|
53
|
-
def queue
|
54
|
-
@queue ||=
|
55
|
-
(
|
56
|
-
case
|
57
|
-
when @uri
|
58
|
-
x = URI.parse(@uri).path
|
59
|
-
else
|
60
|
-
x = ""
|
61
|
-
end
|
62
|
-
# x << "\t" unless x.empty?
|
63
|
-
x.freeze
|
64
|
-
)
|
65
|
-
end
|
66
|
-
def queue_
|
67
|
-
@queue_ ||=
|
68
|
-
(queue.empty? ? queue : queue + " ").freeze
|
69
|
-
end
|
70
|
-
|
71
|
-
# server represents a receiving ZMQ endpoint.
|
72
|
-
def _server_accept_connection! server
|
73
|
-
[ server, @one_way ? nil : server ]
|
74
|
-
end
|
75
|
-
|
76
|
-
# ZMQ is message-oriented, process only one message per "connection".
|
77
|
-
alias :_server_serve_stream :serve_message!
|
78
|
-
|
79
|
-
def stream_eof? stream
|
80
|
-
false
|
81
|
-
end
|
82
|
-
|
83
|
-
# Nothing to be closed for ZMQ.
|
84
|
-
def _server_close_connection! in_stream, out_stream
|
85
|
-
# NOTHING
|
86
|
-
end
|
87
|
-
|
88
|
-
def zmq_uri
|
89
|
-
@zmq_uri ||=
|
90
|
-
(
|
91
|
-
u = URI.parse(uri)
|
92
|
-
u.path = ''
|
93
|
-
u.to_s.freeze
|
94
|
-
)
|
95
|
-
end
|
96
|
-
|
97
|
-
def zmq_context
|
98
|
-
@@zmq_context ||=
|
99
|
-
ZMQ::Context.new(1)
|
100
|
-
end
|
101
|
-
@@zmq_context ||= nil
|
102
|
-
end
|
103
|
-
# !SLIDE END
|
104
|
-
end # class
|
105
|
-
end # module
|
106
|
-
|
107
|
-
|