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 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
-