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 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.
@@ -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
 
@@ -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'
@@ -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'
@@ -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
+
@@ -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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module ASIR
2
- VERSION = "1.0.8"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -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.8
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-11-30 00:00:00.000000000 Z
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: 885978386070956346
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: 885978386070956346
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
-
@@ -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
@@ -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
@@ -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
-