majordomo 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ .rvmrc
@@ -1,17 +1,17 @@
1
-
2
1
  # Majordomo Protocol client example. Uses the mdcli API to hide all MDP aspects
3
2
  # Author : Mark Wotton <mark@ninjablocks.com>, modelled on python
4
3
  # version by Min RK <benjaminrk@gmail.com>
5
4
 
6
5
  require 'majordomo'
7
-
6
+
8
7
  client = Majordomo::Client.new("tcp://localhost:5773", true)
9
8
  count = 0
10
9
  while count < 100000
11
10
  request = "Hello world"
12
11
  begin
13
12
  warn "sending"
14
- reply = client.mdp_send("echo", request)
13
+ reply = client.send_and_receive("echo", request)
14
+ warn "Time out!" unless reply
15
15
  rescue => e
16
16
  warn e
17
17
  warn e.backtrace
@@ -4,7 +4,7 @@ require 'majordomo'
4
4
  worker = Majordomo::Worker.new "tcp://localhost:5773", "echo", true
5
5
  reply = nil
6
6
  while true
7
- request = worker.recv(reply)
7
+ request = worker.receive_and_send(reply)
8
8
  break unless request
9
9
  puts "got a request: #{request}"
10
10
  reply = request # Echo is complex… :-)
data/lib/MDP.rb CHANGED
@@ -7,6 +7,5 @@ module MDP
7
7
  W_WORKER = 'MDPW01'
8
8
 
9
9
  C_CLIENT = 'MDPC01'
10
-
11
-
10
+
12
11
  end
@@ -10,57 +10,47 @@ Based on Java example by Arkadiusz Orzechowski
10
10
  require 'ffi-rzmq'
11
11
 
12
12
  class Majordomo::Client
13
- def initialize broker, verbose=false
13
+
14
+ def initialize(broker, verbose=false)
14
15
  @broker = broker
15
16
  @verbose = verbose
16
17
  @ctx = ZMQ::Context.new
17
18
  @poller = ZMQ::Poller.new
18
19
  @retries = 3
19
20
  @timeout = 2500
20
- reconnect_to_broker()
21
+ reconnect_to_broker
21
22
  end
22
23
 
23
- # Connect or reconnect to broker
24
- def reconnect_to_broker
25
- if @client
26
- @poller.unregister(@client)
27
- @client.close()
28
- end
29
- @client = @ctx.socket(ZMQ::REQ)
30
- @client.setsockopt(ZMQ::LINGER, 0)
31
- @client.connect(@broker)
32
- @poller.register(@client, ZMQ::POLLIN)
33
- warn "I: connecting to broker at #{@broker}…" if @verbose
34
- end
35
-
36
24
  # Send request to broker and get reply by hook or crook.
37
25
  # Takes ownership of request message and destroys it when sent.
38
26
  # Returns the reply message or None if there was no reply.
39
- def mdp_send service, request
27
+ def send_and_receive service, request
40
28
  request = [Majordomo::C_CLIENT, service, request]
41
- warn "I: send request to '#{service}' service: #{request}" if @verbose
29
+ log "I: send request to '#{service}' service: #{request}"
42
30
  reply = nil
43
31
  retries = @retries
44
32
  while retries > 0
45
- warn request
46
33
  @client.send_strings(request)
47
34
  begin
48
35
  items = @poller.poll(@timeout)
49
36
  rescue => e
37
+ items = 0
50
38
  break # interrupted
51
39
  end
52
-
53
- if items
40
+
41
+ if items == -1
42
+ warn "Poller error: Error number #{ZMQ::Util.errno}"
43
+ elsif items > 0
54
44
  msg = []
55
45
  @client.recv_strings(msg)
56
- warn "I: received reply: #{msg}" if @verbose
57
-
46
+ log "I: received reply: #{msg}"
47
+
58
48
  # Don't try to handle errors, just assert noisily
59
49
  raise "expected at least three parts" unless msg.length >= 3
60
50
  header, reply_service, *rest = *msg
61
51
  raise "bad header #{header}" unless Majordomo::C_CLIENT == header
62
52
  raise "bad service #{reply_service}" unless service == reply_service
63
-
53
+
64
54
  reply = rest
65
55
  break
66
56
  else
@@ -76,4 +66,25 @@ class Majordomo::Client
76
66
  end
77
67
  return reply
78
68
  end
69
+
70
+ protected
71
+
72
+ # Connect or reconnect to broker
73
+ def reconnect_to_broker
74
+ if @client
75
+ @poller = ZMQ::Poller.new
76
+ @client.close
77
+ end
78
+ @client = @ctx.socket(ZMQ::REQ)
79
+ @client.setsockopt(ZMQ::LINGER, 0)
80
+ @client.connect(@broker)
81
+ @poller.register(@client, ZMQ::POLLIN)
82
+ log "I: connecting to broker at #{@broker}…"
83
+ end
84
+
85
+ def log(s)
86
+ warn s.inspect if @verbose
87
+ end
88
+
89
+
79
90
  end
@@ -1,3 +1,3 @@
1
1
  module Majordomo
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -11,12 +11,13 @@ require 'ffi-rzmq'
11
11
 
12
12
  class Majordomo::Worker
13
13
  HEARTBEAT_LIVENESS = 3 # 3-5 is reasonable
14
+
14
15
  def initialize(broker, service, verbose=false)
15
- @heartbeat_at = 0 # When to send HEARTBEAT (relative to time.time(), so in seconds)
16
+ @heartbeat_at = 0 # When to send HEARTBEAT
16
17
  @liveness = 0 # How many attempts left
17
18
  @heartbeat = 2500 # Heartbeat delay, msecs
18
19
  @reconnect = 2500 # Reconnect delay, msecs
19
-
20
+
20
21
  # Internal state
21
22
  @expect_reply = false # false only at start
22
23
 
@@ -24,7 +25,6 @@ class Majordomo::Worker
24
25
 
25
26
  # Return address, if any
26
27
  @reply_to = nil
27
-
28
28
 
29
29
  @broker = broker
30
30
  @service = service
@@ -35,20 +35,61 @@ class Majordomo::Worker
35
35
  reconnect_to_broker
36
36
  end
37
37
 
38
+ def receive_and_send(reply=nil)
39
+ # Format and send the reply if we were provided one
40
+ raise "bad reply" unless (reply or not @expect_reply)
41
+
42
+ if reply
43
+ raise "not expecting reply" unless @reply_to
44
+ log reply.inspect
45
+ log reply.class
46
+ reply = [@reply_to, ''] + reply
47
+ send_to_broker Majordomo::W_REPLY, nil, reply
48
+
49
+ @expect_reply = true
50
+ end
51
+ while true
52
+ # Poll socket for a reply, with timeout
53
+ begin
54
+ items = @poller.poll(@timeout)
55
+ rescue => e
56
+ break # Interrupted
57
+ end
58
+ if items
59
+ if (result = handle_message)
60
+
61
+ log "result from handle_message: |#{result}|"
62
+ return result
63
+ end
64
+ else
65
+ reduce_liveness
66
+ end
67
+ # Send HEARTBEAT if it's time
68
+ if Time.now > @heartbeat_at
69
+ send_to_broker(Majordomo::W_HEARTBEAT)
70
+ @heartbeat_at = Time.now + 1e-3*@heartbeat
71
+ end
72
+ end
73
+ log "W: interrupt received, killing worker…"
74
+ return nil
75
+ end
76
+
77
+ protected
78
+
38
79
  def reconnect_to_broker
39
80
  if @worker
40
81
  @poller.unregister(@worker)
41
- @worker.close()
82
+ @worker.close
42
83
  end
43
84
  @worker = @ctx.socket(ZMQ::DEALER)
44
85
 
45
86
  @worker.setsockopt(ZMQ::LINGER, 0)
46
87
  @worker.connect @broker
47
88
  @poller.register @worker, ZMQ::POLLIN
48
- warn "I: connecting to broker at #{@broker}…" if @verbose
89
+ log "I: connecting to broker at #{@broker}…"
49
90
  # Register service with broker
50
91
  send_to_broker Majordomo::W_READY, @service, []
51
-
92
+
52
93
  # If liveness hits zero, queue is considered disconnected
53
94
  @liveness = HEARTBEAT_LIVENESS
54
95
  @heartbeat_at = Time.now + 1e-3 * @heartbeat
@@ -58,99 +99,62 @@ class Majordomo::Worker
58
99
  # @worker.send_string '', ZMQ::SNDMORE
59
100
  # ffi-rzmq is a bit weird about copying in raw bytes. need to
60
101
  # explode the int first
61
-
102
+
62
103
  # @worker.send_msg
63
104
  # @worker.send_string command, ZMQ::SNDMORE
64
-
105
+
65
106
  msg = [option] + msg if option
66
107
 
67
-
108
+
68
109
  msg = ['', Majordomo::W_WORKER, command] + msg
69
110
  if @verbose
70
- warn "I: sending #{command} to broker"
111
+ log "I: sending #{command} to broker"
71
112
  end
72
113
  @worker.send_strings msg
73
114
  end
74
-
75
- def recv(reply=nil)
76
- # Format and send the reply if we were provided one
77
- raise "bad reply" unless (reply or not @expect_reply)
78
-
79
- if reply
80
- raise "not expecting reply" unless @reply_to
81
- warn reply.inspect
82
- warn reply.class
83
- reply = [@reply_to, ''] + reply
84
- send_to_broker Majordomo::W_REPLY, nil, reply
85
-
86
- @expect_reply = true
87
- end
88
- while true
89
- # Poll socket for a reply, with timeout
90
- begin
91
- items = @poller.poll(@timeout)
92
- rescue => e
93
- break # Interrupted
94
- end
95
- if items
96
- if (result = handle_message)
97
115
 
98
- warn "result from handle_message: |#{result}|"
99
- return result
100
- end
101
- else
102
- reduce_liveness
103
- end
104
- # Send HEARTBEAT if it's time
105
- if Time.now > @heartbeat_at
106
- send_to_broker(Majordomo::W_HEARTBEAT)
107
- @heartbeat_at = Time.now + 1e-3*@heartbeat
108
- end
109
- end
110
- logging.warn("W: interrupt received, killing worker…")
111
- return nil
112
- end
113
116
 
114
117
  def handle_message
115
118
  msg = []
116
119
  @worker.recv_strings(msg)
117
- warn "I: received message from broker: #{msg} " if @verbose
118
-
120
+ log "I: received message from broker: #{msg} "
121
+
119
122
  @liveness = @HEARTBEAT_LIVENESS
120
123
  # Don't try to handle errors, just assert noisily
121
124
  raise "expected at least 3 parts" unless msg.length >= 3
122
- warn "full message: #{msg}"
125
+ log "full message: #{msg}"
123
126
  empty, header, command, *rest = *msg
124
127
 
125
128
  raise "no null frame" unless empty == ''
126
129
  raise "bad protocol" unless header == Majordomo::W_WORKER
127
130
  case command
128
131
  when Majordomo::W_REQUEST
129
- warn "request body: #{rest}"
132
+ log "request body: #{rest}"
130
133
  # We should pop and save as many addresses as there are
131
134
  # up to a null part, but for now, just save one…
132
135
  raise "bad message" unless rest.length >= 2
133
136
  @reply_to, empty, *body = *rest
134
- warn "replyto = #{@reply_to}, body=#{body}"
137
+ log "replyto = #{@reply_to}, body=#{body}"
135
138
  # pop empty
136
139
  raise "no null frame" unless empty == ''
137
-
140
+
138
141
  return body # We have a request to process
139
142
  when Majordomo::W_HEARTBEAT
140
143
  # Do nothing for heartbeats
141
144
  when Majordomo::W_DISCONNECT
142
- @reconnect_to_broker
145
+ reconnect_to_broker
143
146
  else
144
- warn "E: invalid input message: #{msg}"
147
+ log "E: invalid input message: #{msg}"
145
148
  end
146
149
  return nil # only return message if we found one
147
150
  end
148
151
 
152
+
149
153
  def reduce_liveness
150
154
  @liveness -= 1
151
155
  if @liveness == 0
152
156
  if @verbose
153
- logging.warn("W: disconnected from broker - retrying…")
157
+ log "W: disconnected from broker - retrying…"
154
158
  end
155
159
  begin
156
160
  time.sleep(1e-3*@reconnect)
@@ -160,4 +164,9 @@ class Majordomo::Worker
160
164
  reconnect_to_broker
161
165
  end
162
166
  end
167
+
168
+ def log(s)
169
+ warn s if @verbose
170
+ end
171
+
163
172
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: majordomo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-03-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi-rzmq
16
- requirement: &14326140 !ruby/object:Gem::Requirement
16
+ requirement: &16157080 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *14326140
24
+ version_requirements: *16157080
25
25
  description: Majordomo for Ruby
26
26
  email:
27
27
  - mark@ninjablocks.com