asir 1.0.8 → 1.1.0
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.
- 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
|
-
|