zoomq 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ gem 'zmachine', path: '../zmachine'
data/lib/zoomq/cli.rb CHANGED
@@ -73,7 +73,7 @@ module ZooMQ
73
73
  "lib/#{name}/client.rb" => "client.rb",
74
74
  "lib/#{name}/console.rb" => "console.rb",
75
75
  "#{name}/server.rb" => "server.rb",
76
- "#{name}/server/ping_request.rb" => "ping_request.rb",
76
+ "#{name}/protocol/ping_request.rb" => "ping_request.rb",
77
77
  }.each do |dest, source|
78
78
  puts " * #{dest}"
79
79
  source = File.join(@root, 'templates', "#{source}.tt")
@@ -0,0 +1,18 @@
1
+ module ZooMQ
2
+ class Client
3
+ class Connection < ZMachine::Connection
4
+
5
+ attr_accessor :client
6
+
7
+ def receive_data(msg)
8
+ msg.unwrap # strip origin
9
+ # TODO: unwrap data to string from bytes to_i wtf
10
+ request_id = String.from_java_bytes(msg.unwrap.data).to_i
11
+ cls = String.from_java_bytes(msg.pop.data).constantize
12
+ obj = cls.parse(String.from_java_bytes(msg.pop.data))
13
+ @client.response(request_id, obj)
14
+ end
15
+
16
+ end
17
+ end
18
+ end
data/lib/zoomq/client.rb CHANGED
@@ -1,25 +1,28 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'zoomq/jeromq-0.3.0-20130721.175323-20.jar'
4
- java_import org.zeromq.ZMQ
5
- java_import org.zeromq.ZContext
6
- java_import org.zeromq.ZMsg
7
- java_import org.zeromq.ZFrame
3
+ require 'zmachine'
8
4
 
9
5
  require 'zoomq/zookeeper'
6
+ require 'zoomq/client/connection'
7
+
8
+ java_import org.zeromq.ZFrame
9
+ java_import java.util.concurrent.atomic.AtomicInteger
10
10
 
11
11
  module ZooMQ
12
- class ServerUnavailable < StandardError; end
12
+ class ServerUnavailableError < StandardError; end
13
+ class TimeoutError < StandardError; end
13
14
 
14
15
  class Client
15
16
 
16
17
  attr_reader :servers
17
18
 
18
- def initialize(service_name, zookeeper_uri, log)
19
- @zk = Zookeeper.new("#{zookeeper_uri}/#{service_name}")
20
- @ctx = ZContext.new
21
- @socket = @ctx.create_socket(ZMQ::ROUTER)
22
- @socket.identity = SecureRandom.uuid.to_java_bytes
19
+ def initialize
20
+ @requests = {}
21
+ @request_id = AtomicInteger.new
22
+ @zk = Zookeeper.new(service_name)
23
+ @channel = ZMachine.connect(nil, ZMQ::ROUTER, Connection) do |connection|
24
+ connection.client = self
25
+ end
23
26
  watch
24
27
  refresh
25
28
  end
@@ -31,27 +34,36 @@ module ZooMQ
31
34
  def refresh
32
35
  @servers = @zk.servers
33
36
  @servers.each do |server|
34
- @socket.connect("tcp://#{server}")
37
+ $log.debug("#{service_name}:connect", server: server)
38
+ @channel.connect("tcp://#{server}")
35
39
  sleep(0.1)
36
40
  end
37
41
  @cycle = @servers.cycle
38
42
  end
39
43
 
40
- def handle(request)
44
+ def request(obj)
41
45
  if @servers.empty?
42
- raise ServerUnavailable.new("no servers are online, please try again later")
46
+ raise ServerUnavailableError.new("no servers are online, please try again later")
43
47
  end
44
48
 
45
49
  server = @cycle.next
46
50
 
47
- msg = ZMsg.new_string_msg(request.class.to_s, request.to_s)
51
+ deferred = ZMachine::DefaultDeferrable.new
52
+ deferred.callback { |result| yield result } if block_given?
53
+
54
+ request_id = @request_id.increment_and_get
55
+ msg = ZMsg.new_string_msg(obj.class.to_s, obj.to_s)
56
+ msg.wrap(ZFrame.new(request_id.to_s))
48
57
  msg.wrap(ZFrame.new(server))
49
- msg.send(@socket)
58
+ $log.debug("#{service_name}:request", id: request_id, obj: obj.inspect)
59
+ @channel.send_data(msg)
60
+
61
+ @requests[request_id] = deferred
62
+ end
50
63
 
51
- msg = ZMsg.recvMsg(@socket)
52
- msg.unwrap
53
- cls = String.from_java_bytes(msg.pop.data).constantize
54
- cls.parse(String.from_java_bytes(msg.pop.data))
64
+ def response(request_id, obj)
65
+ $log.debug("#{service_name}:response", id: request_id, obj: obj.inspect)
66
+ @requests[request_id].succeed(obj)
55
67
  end
56
68
 
57
69
  end
@@ -0,0 +1,34 @@
1
+ require 'ap'
2
+ require 'irb'
3
+ require 'ripl'
4
+
5
+ Ripl::Shell.class_eval do
6
+ def format_result(result)
7
+ ap(result)
8
+ end
9
+ end
10
+
11
+ module ZooMQ
12
+ class Console
13
+ def initialize
14
+ $log.level = :info
15
+ Thread.new { zmachine }
16
+ Ripl.start(binding: binding)
17
+ end
18
+
19
+ def zmachine
20
+ ZMachine.run { client }
21
+ end
22
+
23
+ def method_missing(name, *args, &block)
24
+ result = nil
25
+ df = @client.send(name, *args, &block)
26
+ df.callback { |response| result = response }
27
+ df.errback { |error| result = error }
28
+ while result.nil?
29
+ sleep(0.1)
30
+ end
31
+ result
32
+ end
33
+ end
34
+ end
@@ -1,24 +1,23 @@
1
1
  java_import org.zeromq.ZMsg
2
2
 
3
- require 'zoomq/handler'
3
+ require 'zmachine/connection'
4
4
 
5
5
  module ZooMQ
6
6
  class Server
7
- class RequestHandler < Handler
8
- def handle(zloop, poller, worker)
9
- @server = worker.server
10
- origin, msg = recv_msg(poller.socket)
7
+ class Connection < ZMachine::Connection
8
+
9
+ attr_accessor :server
10
+
11
+ def receive_data(msg)
12
+ origin = msg.unwrap
13
+ request_id = msg.unwrap
11
14
  result = handle_msg(msg)
15
+ result.wrap(request_id)
12
16
  result.wrap(origin)
13
- result.send(poller.socket)
17
+ send_data(result)
14
18
  return 0
15
19
  end
16
20
 
17
- def recv_msg(socket)
18
- msg = ZMsg.recvMsg(socket)
19
- [msg.unwrap, msg]
20
- end
21
-
22
21
  def handle_msg(msg)
23
22
  cls = String.from_java_bytes(msg.pop.data).constantize
24
23
  request = cls.parse(String.from_java_bytes(msg.pop.data))
@@ -1,8 +1,7 @@
1
1
  java_import org.zeromq.ZMQ
2
- java_import org.zeromq.ZContext
3
- java_import org.zeromq.ZLoop
4
2
 
5
- require 'zoomq/server/request_handler'
3
+ require 'zmachine'
4
+ require 'zoomq/server/connection'
6
5
 
7
6
  module ZooMQ
8
7
  class Server
@@ -12,23 +11,22 @@ module ZooMQ
12
11
 
13
12
  def initialize(server)
14
13
  @server = server
15
- @zloop = ZLoop.new
16
- @zloop.verbose(true)
17
- initialize_socket
18
14
  end
19
15
 
20
- def initialize_socket
21
- @socket = @server.create_socket(ZMQ::ROUTER)
22
- @port = @socket.bind("tcp://*:*")
23
- RequestHandler.new(@socket).register(@zloop, self)
24
- Thread.current.name = "#{@server.fqdn}:#{@port}"
25
- @socket.identity = Thread.current[:name].to_java_bytes
16
+ def run
17
+ ZMachine.run { initialize_socket }
26
18
  end
27
19
 
28
- def run
29
- @server.log.info("pubdater:worker", run: true, announce: @socket.identity)
30
- @server.announce(@socket.identity)
31
- @zloop.start
20
+ def initialize_socket
21
+ $log.info("zoomq:server:worker", bind: "tcp://*:*")
22
+ ZMachine.start_server("tcp://*:*", ZMQ::ROUTER, Connection) do |handler|
23
+ identity = "#{@server.fqdn}:#{handler.channel.port}"
24
+ $log.info("zoomq:server:worker", announce: identity)
25
+ Thread.current.name = "ZMQ::Server::Worker (#{identity})"
26
+ handler.channel.identity = identity
27
+ handler.server = @server
28
+ @server.announce(identity)
29
+ end
32
30
  end
33
31
 
34
32
  end
data/lib/zoomq/server.rb CHANGED
@@ -1,9 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'zoomq/jeromq-0.3.0-20130721.175323-20.jar'
4
- java_import org.zeromq.ZMQ
5
-
6
3
  require 'forwardable'
4
+ require 'socket'
5
+ require 'zmachine'
7
6
 
8
7
  require 'zoomq/zookeeper'
9
8
  require 'zoomq/server/worker'
@@ -13,25 +12,29 @@ module ZooMQ
13
12
 
14
13
  extend Forwardable
15
14
  def_delegators :@zk, :globals, :locals, :announce
16
- def_delegators :@ctx, :create_socket
17
15
 
18
- attr_reader :log, :fqdn, :port
16
+ attr_reader :fqdn, :port
17
+
18
+ def initialize
19
+ $log.info("#{service_name}:initialize #{RUBY_DESCRIPTION}")
20
+ $log.info("#{service_name}:initialize", {
21
+ env: Env.mode,
22
+ })
19
23
 
20
- def initialize(service_name, zookeeper_uri, log)
21
24
  Signal.register_shutdown_handler { shutdown }
22
- @log = log
23
- @zk = Zookeeper.new("#{zookeeper_uri}/#{service_name}")
24
- @ctx = ZContext.new
25
- @fqdn = Socket.gethostbyname(Socket.gethostname).first
25
+ @fqdn = ::Socket.gethostbyname(::Socket.gethostname).first
26
+ @zk = Zookeeper.new(service_name)
26
27
  end
27
28
 
28
29
  def run
30
+ # TODO: make it multi-threaded
31
+ $log.info("#{service_name}:run", workers: 1)
29
32
  Worker.new(self).run
30
33
  end
31
34
 
32
35
  def shutdown
33
- @ctx.destroy if @ctx
34
36
  @zk.close if @zk
37
+ ZMachine.stop_event_loop
35
38
  end
36
39
 
37
40
  end
@@ -0,0 +1,43 @@
1
+ java_import org.zeromq.ZMQ
2
+
3
+ require 'zmachine/connection'
4
+
5
+ module ZooMQ
6
+ class Socket < ZMachine::Connection
7
+ READABLES = [ ZMQ::SUB, ZMQ::PULL, ZMQ::ROUTER, ZMQ::DEALER, ZMQ::REP, ZMQ::REQ, ZMQ::PAIR ]
8
+ WRITABLES = [ ZMQ::PUB, ZMQ::PUSH, ZMQ::ROUTER, ZMQ::DEALER, ZMQ::REP, ZMQ::REQ, ZMQ::PAIR ]
9
+
10
+ def initialize(socket, socket_type, server)
11
+ @socket, @socket_type, @server = socket, socket_type, server
12
+ self.notify_readable = true if READABLES.include?(socket_type)
13
+ #self.notify_writable = true if WRITABLES.include?(socket_type)
14
+ end
15
+
16
+ def notify_readable
17
+ # Not sure if this is actually necessary. I suppose it prevents us
18
+ # from having to to instantiate a ZMQ::Message unnecessarily.
19
+ # I'm leaving this in because its in the docs, but it could probably
20
+ # be taken out.
21
+ return unless readable?
22
+ handle_readable
23
+ end
24
+
25
+ #def notify_writable
26
+ # return unless writable?
27
+
28
+ # # once a writable event is successfully received the socket
29
+ # # should be accepting messages again so stop triggering
30
+ # # write events
31
+ # self.notify_writable = false
32
+ # handle_writable
33
+ #end
34
+
35
+ def readable?
36
+ (@socket.events & ZMQ::Poller::POLLIN) == ZMQ::Poller::POLLIN
37
+ end
38
+
39
+ def writable?
40
+ (@socket.events & ZMQ::Poller::POLLOUT) == ZMQ::Poller::POLLOUT
41
+ end
42
+ end
43
+ end
@@ -7,8 +7,8 @@ module ZooMQ
7
7
  attr_reader :globals
8
8
  attr_reader :locals
9
9
 
10
- def initialize(uri)
11
- @zk = ZK.new(uri)
10
+ def initialize(service_name)
11
+ @zk = ZK.new("#{$conf.zookeeper}/#{service_name}")
12
12
  @zk.mkdir_p("/alive")
13
13
  @globals = KeySpace.new(:global, @zk)
14
14
  end
@@ -1,24 +1,18 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'forwardable'
4
3
  require 'zoomq/client'
5
4
 
6
5
  require '<%=config[:name]%>/protocol'
7
6
 
8
7
  module <%=config[:constant_name]%>
9
- class Client
8
+ class Client < ZooMQ::Client
10
9
 
11
- extend Forwardable
12
-
13
- def initialize(zookeeper, log)
14
- @client = ZooMQ::Client.new(<%=config[:name].inspect%>, zookeeper, log)
10
+ def service_name
11
+ <%=config[:name].inspect%>
15
12
  end
16
13
 
17
- def_delegators :@client, :servers
18
-
19
14
  def ping
20
- request = PingRequest.new
21
- @client.handle(request)
15
+ request(PingRequest.new)
22
16
  end
23
17
 
24
18
  end
@@ -1,29 +1,10 @@
1
- require 'ap'
2
- require 'irb'
3
- require 'ripl'
4
- require 'forwardable'
5
-
1
+ require 'zoomq/console'
6
2
  require '<%=config[:name]%>/client'
7
3
 
8
- Ripl::Shell.class_eval do
9
- def format_result(result)
10
- ap(result)
11
- end
12
- end
13
-
14
4
  module <%=config[:constant_name]%>
15
- class Console
16
-
17
- extend Forwardable
18
- def initialize
19
- $log.level = :info
20
- @client = Client.new($conf.zookeeper, $log)
21
- Ripl.start(binding: binding)
22
- end
23
-
24
- def method_missing(name, *args, &block)
25
- @client.__send__(name, *args, &block)
5
+ class Console < ZooMQ::Console
6
+ def client
7
+ @client = Client.new
26
8
  end
27
-
28
9
  end
29
10
  end
@@ -1,9 +1,11 @@
1
1
  require '<%=config[:name]%>/protocol'
2
2
 
3
3
  module <%=config[:constant_name]%>
4
- class PingRequest
5
- def handle(server)
6
- PingResponse.new
4
+ module Protocol
5
+ class PingRequest
6
+ def handle(server)
7
+ PingResponse.new
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -1,4 +1,4 @@
1
- package <%=config[:name]%>;
1
+ package <%=config[:name]%>.protocol;
2
2
 
3
3
  message PingRequest {
4
4
  }
@@ -9,18 +9,8 @@ end
9
9
  module <%=config[:constant_name]%>
10
10
  class Server
11
11
 
12
- def initialize
13
- $log.info("<%=config[:name]%>:initialize #{RUBY_DESCRIPTION}")
14
- $log.info("<%=config[:name]%>:initialize", {
15
- env: Env.mode,
16
- })
17
-
18
- @server = ZooMQ::Server.new(<%=config[:name].inspect%>, $conf.zookeeper, $log)
19
- end
20
-
21
- def run
22
- $log.info("<%=config[:name]%>:run")
23
- @server.run
12
+ def service_name
13
+ <%=config[:name].inspect%>
24
14
  end
25
15
 
26
16
  end
data/zoomq.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "zoomq"
5
- spec.version = "0.1.1"
5
+ spec.version = "0.2.0"
6
6
  spec.authors = ["madvertise Mobile Advertising GmbH"]
7
7
  spec.email = ["tech@madvertise.com"]
8
8
  spec.description = %q{ØMQ ROUTER/ROUTER coordinated by Zookeeper}
@@ -21,4 +21,5 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency "multi_json"
22
22
  spec.add_dependency "ruby-protocol-buffers"
23
23
  spec.add_dependency "zk"
24
+ spec.add_dependency "zmachine"
24
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zoomq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.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: 2013-08-06 00:00:00.000000000 Z
12
+ date: 2013-08-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: erubis
@@ -107,6 +107,22 @@ dependencies:
107
107
  none: false
108
108
  prerelease: false
109
109
  type: :runtime
110
+ - !ruby/object:Gem::Dependency
111
+ name: zmachine
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - '>='
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ none: false
118
+ requirement: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ none: false
124
+ prerelease: false
125
+ type: :runtime
110
126
  description: ØMQ ROUTER/ROUTER coordinated by Zookeeper
111
127
  email:
112
128
  - tech@madvertise.com
@@ -123,11 +139,12 @@ files:
123
139
  - bin/zoomq
124
140
  - lib/zoomq/cli.rb
125
141
  - lib/zoomq/client.rb
126
- - lib/zoomq/handler.rb
127
- - lib/zoomq/jeromq-0.3.0-20130721.175323-20.jar
142
+ - lib/zoomq/client/connection.rb
143
+ - lib/zoomq/console.rb
128
144
  - lib/zoomq/server.rb
129
- - lib/zoomq/server/request_handler.rb
145
+ - lib/zoomq/server/connection.rb
130
146
  - lib/zoomq/server/worker.rb
147
+ - lib/zoomq/socket.rb
131
148
  - lib/zoomq/zookeeper.rb
132
149
  - templates/Gemfile.tt
133
150
  - templates/LICENSE.txt.tt
data/lib/zoomq/handler.rb DELETED
@@ -1,13 +0,0 @@
1
- java_import org.zeromq.ZMQ
2
-
3
- module ZooMQ
4
- class Handler
5
- def initialize(socket, flags=ZMQ::Poller::POLLIN)
6
- @poller = ZMQ::PollItem.new(socket, flags)
7
- end
8
-
9
- def register(zloop, opts)
10
- zloop.add_poller(@poller, self, opts)
11
- end
12
- end
13
- end