combi 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/lib/combi.rb +32 -0
- data/lib/combi/buses/bus.rb +18 -21
- data/lib/combi/buses/queue.rb +4 -4
- data/lib/combi/buses/web_socket.rb +10 -11
- data/lib/combi/queue_service.rb +91 -98
- data/lib/combi/reactor.rb +29 -36
- data/lib/combi/response_store.rb +29 -31
- data/lib/combi/service.rb +37 -41
- data/lib/combi/service_bus.rb +21 -24
- data/lib/combi/version.rb +1 -1
- data/spec/lib/combi/buses/bus_spec.rb +1 -5
- data/spec/lib/combi/buses/queue_spec.rb +1 -1
- data/spec/support/rabbitmq_server.rb +8 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 929a53569645c090a360edc9fdfdb0a96ba436b9
|
4
|
+
data.tar.gz: 4557b6eb644fb82dda359e1cd12fd4298b570e28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9060e9b6d9eda5dea793471870156502765b0f105b20f026af987491db76e97fca336ce6773df9c00f86a078897ebf7aa8e1e7b1ed09e937e1bfd09734da3ae
|
7
|
+
data.tar.gz: 9e7d357112557849289c2438cc76d8502f18ac487c95c274a5632269d7c5e25a582af7559817c0f7058bfa3cf00ee8d281ba9c57e82ea9e89e11b28e9f4e8f6c
|
data/lib/combi.rb
CHANGED
@@ -1,2 +1,34 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Combi
|
4
|
+
def self.logger
|
5
|
+
@logger ||= create_logger
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.logger_class
|
9
|
+
@logger_class ||= Logger
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.logger_class=(custom_class)
|
13
|
+
@logger_class = custom_class
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def self.create_logger
|
19
|
+
if ENV['LOG_LEVEL'] and Logger::Severity.const_defined?(ENV['LOG_LEVEL'])
|
20
|
+
severity = Logger::Severity.const_get(ENV['LOG_LEVEL'])
|
21
|
+
elsif ENV['LOG_LEVEL'] == 'NONE'
|
22
|
+
severity = Logger::Severity::UNKNOWN
|
23
|
+
elsif ENV['DEBUG'] == 'true'
|
24
|
+
severity = Logger::Severity::DEBUG
|
25
|
+
else
|
26
|
+
severity = Logger::Severity::INFO
|
27
|
+
end
|
28
|
+
logger = logger_class.new(STDOUT)
|
29
|
+
logger.level = severity
|
30
|
+
return logger
|
31
|
+
end
|
32
|
+
end
|
1
33
|
require 'combi/version'
|
2
34
|
require 'combi/service_bus'
|
data/lib/combi/buses/bus.rb
CHANGED
@@ -55,11 +55,6 @@ module Combi
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
def log(message)
|
59
|
-
return unless @debug_mode ||= ENV['DEBUG'] == 'true'
|
60
|
-
puts "#{Time.now.to_f} #{self.class.name} #{message}"
|
61
|
-
end
|
62
|
-
|
63
58
|
protected
|
64
59
|
|
65
60
|
def make_service_instance(service_definition)
|
@@ -98,7 +93,7 @@ module Combi
|
|
98
93
|
|
99
94
|
def add_route_for(service_name, action_name, service_instance)
|
100
95
|
path = [service_name, action_name].join('/')
|
101
|
-
|
96
|
+
Combi.logger.info {"New route: #{path} :: #{service_instance}"}
|
102
97
|
@routes[path] = service_instance
|
103
98
|
end
|
104
99
|
|
@@ -112,8 +107,8 @@ module Combi
|
|
112
107
|
def resolve_route(service_name, kind)
|
113
108
|
path = [service_name, kind].join('/')
|
114
109
|
return @routes[path] if @routes[path]
|
115
|
-
|
116
|
-
|
110
|
+
Combi.logger.warn {"Service Path #{path} not found"}
|
111
|
+
Combi.logger.warn {"routes: #{@routes.keys.inspect}"}
|
117
112
|
raise UnknownStop.new(path)
|
118
113
|
end
|
119
114
|
|
@@ -128,14 +123,14 @@ module Combi
|
|
128
123
|
deferrable.errback &log_service_invocation(false, t0, path)
|
129
124
|
deferrable
|
130
125
|
rescue StandardError => e
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
126
|
+
Combi.logger.error do
|
127
|
+
require 'yaml'
|
128
|
+
msg = " *** ERROR INVOKING SERVICE ***" +
|
129
|
+
" - #{e.inspect}" +
|
130
|
+
" - #{service_name} #{service_instance.class.ancestors.join ' > '}" +
|
131
|
+
" - #{action}" +
|
132
|
+
" - #{params.to_yaml.split("\n").join("\n\t")}"
|
133
|
+
end
|
139
134
|
return sync_to_async error: { klass: e.class.name, message: e.message, backtrace: e.backtrace }
|
140
135
|
end
|
141
136
|
|
@@ -152,11 +147,13 @@ module Combi
|
|
152
147
|
|
153
148
|
def log_service_invocation(success, t0, path)
|
154
149
|
Proc.new do |response|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
150
|
+
Combi.logger.info do
|
151
|
+
result = success ? 'OK' : 'KO'
|
152
|
+
time = '%10.6fs' % (Time.now - t0)
|
153
|
+
base_msg = "#{result}\t#{time}\t#{path}"
|
154
|
+
base_msg += "\t#{response.inspect}" if success == false
|
155
|
+
base_msg
|
156
|
+
end
|
160
157
|
end
|
161
158
|
end
|
162
159
|
|
data/lib/combi/buses/queue.rb
CHANGED
@@ -31,13 +31,13 @@ module Combi
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def create_queue_for_service(service_name)
|
34
|
-
|
34
|
+
Combi.logger.debug {"creating queue #{service_name}"}
|
35
35
|
queue_options = {}
|
36
36
|
subscription_options = {}
|
37
37
|
subscription_options[:ack] = true
|
38
38
|
queue_service.ready do
|
39
39
|
queue_service.queue(service_name.to_s, queue_options) do |queue|
|
40
|
-
|
40
|
+
Combi.logger.debug {"subscribing to queue #{service_name.to_s}"}
|
41
41
|
queue.subscribe(subscription_options) do |delivery_info, payload|
|
42
42
|
process_queue_message service_name, payload, delivery_info
|
43
43
|
queue_service.acknowledge delivery_info
|
@@ -47,7 +47,7 @@ module Combi
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def request(name, kind, message, timeout: RPC_DEFAULT_TIMEOUT, fast: false)
|
50
|
-
|
50
|
+
Combi.logger.debug {"Preparing request: #{name}.#{kind} #{message.inspect[0..500]}\t|| timeout: #{timeout} fast: #{fast}"}
|
51
51
|
options = {
|
52
52
|
timeout: timeout,
|
53
53
|
routing_key: name.to_s
|
@@ -60,7 +60,7 @@ module Combi
|
|
60
60
|
waiter = @response_store.wait_for correlation_id, timeout
|
61
61
|
end
|
62
62
|
queue_service.next_ready_only do
|
63
|
-
|
63
|
+
Combi.logger.debug {"Making request: #{name}.#{kind} #{message.inspect[0..500]}\t|| #{options.inspect[0..500]}"}
|
64
64
|
queue_service.publish_request(kind, message, options)
|
65
65
|
end
|
66
66
|
waiter
|
@@ -18,12 +18,12 @@ module Combi
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def on_open(ws, handler)
|
21
|
-
|
21
|
+
Combi.logger.debug { "ON OPEN #{handler.inspect}" }
|
22
22
|
handler.new_session(ws)
|
23
23
|
end
|
24
24
|
|
25
25
|
def on_message(ws, session, raw_message)
|
26
|
-
|
26
|
+
Combi.logger.debug {"WS SERVER ON MESSAGE #{raw_message[0..500]}"}
|
27
27
|
message = Yajl::Parser.parse raw_message, symbolize_keys: true
|
28
28
|
@bus.on_message(ws, message, session)
|
29
29
|
end
|
@@ -49,7 +49,7 @@ module Combi
|
|
49
49
|
|
50
50
|
def stop!
|
51
51
|
ws && ws.close
|
52
|
-
|
52
|
+
Combi.logger.debug {"stop requested"}
|
53
53
|
end
|
54
54
|
|
55
55
|
def restart!
|
@@ -58,29 +58,28 @@ module Combi
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def open_websocket
|
61
|
-
|
61
|
+
Combi.logger.debug { "Remote API #{@remote_api}" }
|
62
62
|
@ws = ws = Faye::WebSocket::Client.new(@remote_api)
|
63
63
|
ws.on :open do |event|
|
64
|
-
|
65
|
-
@bus.log "HANDLER #{@handler.inspect}"
|
64
|
+
Combi.logger.debug {"OPEN WITH HANDLER #{@handler.inspect}"}
|
66
65
|
@handler.on_open if @handler.respond_to?(:on_open)
|
67
66
|
@bus.ready.succeed
|
68
67
|
end
|
69
68
|
|
70
69
|
ws.on :message do |event|
|
71
|
-
|
70
|
+
Combi.logger.debug {"ON MESSAGE: #{event.data[0..500]}"}
|
72
71
|
message = Yajl::Parser.parse event.data, symbolize_keys: true
|
73
72
|
@bus.on_message(ws, message)
|
74
73
|
end
|
75
74
|
|
76
75
|
ws.on :close do |event|
|
77
|
-
|
76
|
+
Combi.logger.debug {"close #{event.code}: #{event.reason}"}
|
78
77
|
@handler.on_close if @handler.respond_to?(:on_close)
|
79
78
|
@ws = ws = nil
|
80
79
|
end
|
81
80
|
|
82
81
|
ws.on :error do |event|
|
83
|
-
|
82
|
+
Combi.logger.debug {"received error: #{event.inspect}"}
|
84
83
|
stop!
|
85
84
|
end
|
86
85
|
end
|
@@ -157,7 +156,7 @@ module Combi
|
|
157
156
|
def on_message(ws, message, session = nil)
|
158
157
|
if message[:correlation_id] && message.has_key?(:result)
|
159
158
|
@response_store.handle_rpc_response(message)
|
160
|
-
|
159
|
+
Combi.logger.debug {"Handled response with correlation_id #{message[:correlation_id]} - #{message.inspect[0..500]}"}
|
161
160
|
return
|
162
161
|
end
|
163
162
|
service_name = message[:service]
|
@@ -207,7 +206,7 @@ module Combi
|
|
207
206
|
web_socket = @machine.respond_to?(:ws) ? @machine.ws : ws
|
208
207
|
unless web_socket.nil?
|
209
208
|
serialized = Yajl::Encoder.encode msg
|
210
|
-
|
209
|
+
Combi.logger.debug {"sending request #{serialized}"}
|
211
210
|
web_socket.send serialized
|
212
211
|
end
|
213
212
|
end
|
data/lib/combi/queue_service.rb
CHANGED
@@ -1,129 +1,122 @@
|
|
1
1
|
require 'amqp'
|
2
2
|
require 'amqp/utilities/event_loop_helper'
|
3
3
|
|
4
|
-
|
5
|
-
class QueueService
|
4
|
+
class Combi::QueueService
|
6
5
|
|
7
|
-
|
6
|
+
attr_accessor :rpc_callback
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
def ready(&block)
|
18
|
-
@ready_callbacks << block
|
19
|
-
@ready_defer.callback &block
|
20
|
-
end
|
8
|
+
def initialize(config, options)
|
9
|
+
@config = config
|
10
|
+
@options = options
|
11
|
+
@rpc_queue = nil
|
12
|
+
@ready_defer = EventMachine::DefaultDeferrable.new
|
13
|
+
@ready_callbacks = []
|
14
|
+
end
|
21
15
|
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
def ready(&block)
|
17
|
+
@ready_callbacks << block
|
18
|
+
@ready_defer.callback &block
|
19
|
+
end
|
25
20
|
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
def next_ready_only(&block)
|
22
|
+
@ready_defer.callback &block
|
23
|
+
end
|
29
24
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
25
|
+
def status
|
26
|
+
@amqp_conn && @amqp_conn.status
|
27
|
+
end
|
34
28
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
29
|
+
def start
|
30
|
+
@config[:reconnect_period] ||= 4
|
31
|
+
reconnection_proc = Proc.new { EM.add_timer(@config[:reconnect_period] * rand) { start } }
|
32
|
+
@config[:on_tcp_connection_failure] = reconnection_proc
|
33
|
+
@config[:on_possible_authentication_failure] = reconnection_proc
|
34
|
+
connect @config do
|
35
|
+
if @options[:rpc] == :enabled
|
36
|
+
create_rpc_queue
|
37
|
+
else
|
38
|
+
@ready_defer.succeed
|
46
39
|
end
|
47
40
|
end
|
41
|
+
end
|
48
42
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
reconnect
|
61
|
-
end
|
62
|
-
end
|
63
|
-
connection.on_tcp_connection_loss do |conn, settings|
|
64
|
-
puts "[ERROR] Connection failed, resetting for reconnect"
|
43
|
+
def connect(config, &after_connect)
|
44
|
+
Combi.logger.info {"trying to connect to queue server"}
|
45
|
+
@amqp_conn = AMQP.connect(config) do |connection, open_ok|
|
46
|
+
@channel = AMQP::Channel.new @amqp_conn
|
47
|
+
@channel.auto_recovery = true
|
48
|
+
@exchange = @channel.direct ''
|
49
|
+
after_connect.call
|
50
|
+
connection.on_error do |conn, connection_close|
|
51
|
+
Combi.logger.info {"[amqp connection.close] Reply code = #{connection_close.reply_code}, reply text = #{connection_close.reply_text}"}
|
52
|
+
if connection_close.reply_code == 320
|
53
|
+
Combi.logger.info {"[amqp connection.close] Setting up a periodic reconnection timer..."}
|
65
54
|
reconnect
|
66
55
|
end
|
67
56
|
end
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
@ready_defer = EventMachine::DefaultDeferrable.new
|
72
|
-
@ready_callbacks.each do |callback|
|
73
|
-
@ready_defer.callback &callback
|
57
|
+
connection.on_tcp_connection_loss do |conn, settings|
|
58
|
+
Combi.logger.error {"Connection failed, resetting for reconnect"}
|
59
|
+
reconnect
|
74
60
|
end
|
75
|
-
start
|
76
61
|
end
|
62
|
+
end
|
77
63
|
|
78
|
-
|
79
|
-
|
64
|
+
def reconnect
|
65
|
+
@ready_defer = EventMachine::DefaultDeferrable.new
|
66
|
+
@ready_callbacks.each do |callback|
|
67
|
+
@ready_defer.callback &callback
|
80
68
|
end
|
69
|
+
start
|
70
|
+
end
|
81
71
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
86
|
-
end
|
72
|
+
def disconnect
|
73
|
+
@amqp_conn.close
|
74
|
+
end
|
87
75
|
|
88
|
-
|
89
|
-
|
76
|
+
def publish(*args, &block)
|
77
|
+
@exchange.publish *args do
|
78
|
+
block.call if block_given?
|
90
79
|
end
|
80
|
+
end
|
91
81
|
|
92
|
-
|
93
|
-
|
94
|
-
|
82
|
+
def queue(name, options = {}, &block)
|
83
|
+
@channel.queue(name, options, &block)
|
84
|
+
end
|
95
85
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
end
|
86
|
+
def acknowledge(delivery_info)
|
87
|
+
@channel.acknowledge(delivery_info.delivery_tag, false)
|
88
|
+
end
|
100
89
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
rpc_queue.subscribe do |metadata, response|
|
106
|
-
parsed_response = Yajl::Parser.parse response, symbolize_keys: true
|
107
|
-
message = {
|
108
|
-
correlation_id: metadata.correlation_id,
|
109
|
-
response: parsed_response
|
110
|
-
}
|
111
|
-
rpc_callback.call(message) unless rpc_callback.nil?
|
112
|
-
end
|
113
|
-
@ready_defer.succeed
|
114
|
-
end
|
115
|
-
end
|
90
|
+
def respond(response, delivery_info)
|
91
|
+
serialized = Yajl::Encoder.encode response
|
92
|
+
publish serialized, routing_key: delivery_info.reply_to, correlation_id: delivery_info.correlation_id
|
93
|
+
end
|
116
94
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
95
|
+
def create_rpc_queue
|
96
|
+
@rpc_queue.unsubscribe unless @rpc_queue.nil?
|
97
|
+
@rpc_queue = queue('', exclusive: true, auto_delete: true) do |rpc_queue|
|
98
|
+
Combi.logger.debug {"\tRPC QUEUE: #{@rpc_queue.name}"}
|
99
|
+
rpc_queue.subscribe do |metadata, response|
|
100
|
+
parsed_response = Yajl::Parser.parse response, symbolize_keys: true
|
101
|
+
message = {
|
102
|
+
correlation_id: metadata.correlation_id,
|
103
|
+
response: parsed_response
|
104
|
+
}
|
105
|
+
rpc_callback.call(message) unless rpc_callback.nil?
|
121
106
|
end
|
122
|
-
|
123
|
-
log "sending request #{kind} #{message.inspect[0..500]} with options #{options.inspect}"
|
124
|
-
request = Yajl::Encoder.encode kind: kind, payload: message, options: {}
|
125
|
-
publish request, options
|
107
|
+
@ready_defer.succeed
|
126
108
|
end
|
109
|
+
end
|
127
110
|
|
111
|
+
def publish_request(kind, message, options = {})
|
112
|
+
if options.has_key? :correlation_id
|
113
|
+
# wants a response
|
114
|
+
options[:reply_to] = @rpc_queue.name
|
115
|
+
end
|
116
|
+
options[:expiration] = ((options[:timeout] || RPC_DEFAULT_TIMEOUT) * 1000).to_i
|
117
|
+
Combi.logger.debug {"sending request #{kind} #{message.inspect[0..500]} with options #{options.inspect}"}
|
118
|
+
request = Yajl::Encoder.encode kind: kind, payload: message, options: {}
|
119
|
+
publish request, options
|
128
120
|
end
|
121
|
+
|
129
122
|
end
|
data/lib/combi/reactor.rb
CHANGED
@@ -1,47 +1,40 @@
|
|
1
1
|
require 'eventmachine'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
STDERR << "\t#{error.backtrace.join("\t\n")}" << "\n"
|
10
|
-
end
|
11
|
-
log "-EM.start- the reactor is running: #{EM::reactor_running?}"
|
12
|
-
raise "EM did not shut down" if EM::reactor_running?
|
13
|
-
@@reactor_thread = Thread.new do
|
14
|
-
begin
|
15
|
-
log "------- starting EM reactor"
|
16
|
-
EM::run do
|
17
|
-
log "------- reactor started"
|
18
|
-
block.call unless block.nil?
|
19
|
-
end
|
20
|
-
ensure
|
21
|
-
puts "------- reactor stopped"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
30.times do
|
25
|
-
sleep 0.1 unless EM::reactor_running?
|
26
|
-
end
|
3
|
+
class Combi::Reactor
|
4
|
+
def self.start(&block)
|
5
|
+
EM::error_handler do |error|
|
6
|
+
STDERR << "ERROR IN EM\n"
|
7
|
+
STDERR << "\t#{error.inspect}"
|
8
|
+
STDERR << "\t#{error.backtrace.join("\t\n")}" << "\n"
|
27
9
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
10
|
+
Combi.logger.info {"-EM.start- the reactor is running: #{EM::reactor_running?}"}
|
11
|
+
raise "EM did not shut down" if EM::reactor_running?
|
12
|
+
@@reactor_thread = Thread.new do
|
13
|
+
begin
|
14
|
+
Combi.logger.debug {"------- starting EM reactor"}
|
15
|
+
EM::run do
|
16
|
+
Combi.logger.debug {"------- reactor started"}
|
17
|
+
block.call unless block.nil?
|
18
|
+
end
|
19
|
+
ensure
|
20
|
+
Combi.logger.info {"------- reactor stopped"}
|
34
21
|
end
|
35
22
|
end
|
36
|
-
|
37
|
-
|
38
|
-
@@reactor_thread.join if @@reactor_thread
|
23
|
+
30.times do
|
24
|
+
sleep 0.1 unless EM::reactor_running?
|
39
25
|
end
|
26
|
+
end
|
40
27
|
|
41
|
-
|
42
|
-
|
43
|
-
|
28
|
+
def self.stop
|
29
|
+
Combi.logger.debug {"-EM.stop- the reactor is running: #{EM::reactor_running?}"}
|
30
|
+
EM::stop_event_loop if EM::reactor_running?
|
31
|
+
50.times do
|
32
|
+
sleep 0.3 if EM::reactor_running?
|
44
33
|
end
|
34
|
+
end
|
45
35
|
|
36
|
+
def self.join_thread
|
37
|
+
@@reactor_thread.join if @@reactor_thread
|
46
38
|
end
|
39
|
+
|
47
40
|
end
|
data/lib/combi/response_store.rb
CHANGED
@@ -1,41 +1,39 @@
|
|
1
1
|
require 'eventmachine'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
3
|
+
class Combi::ResponseStore
|
4
|
+
def initialize()
|
5
|
+
@waiters = {}
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
# Returns an EM::Deferrable
|
9
|
+
def wait_for(correlation_id, timeout)
|
10
|
+
waiter = EM::DefaultDeferrable.new
|
11
|
+
add_waiter correlation_id, waiter
|
12
|
+
waiter.timeout timeout, error: 'Timeout::Error'
|
13
|
+
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
15
|
+
def handle_rpc_response(response)
|
16
|
+
correlation_id = response[:correlation_id]
|
17
|
+
waiter = @waiters[correlation_id]
|
18
|
+
return unless waiter
|
19
|
+
response = response[:response] #Yajl::Parser.parse response[:response], sybolize_keys: true
|
20
|
+
if response.respond_to?(:keys) and response[:error]
|
21
|
+
waiter.fail response
|
22
|
+
else
|
23
|
+
waiter.succeed response
|
26
24
|
end
|
25
|
+
end
|
27
26
|
|
28
|
-
|
27
|
+
protected
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
29
|
+
def add_waiter(correlation_id, waiter)
|
30
|
+
@waiters[correlation_id] = waiter
|
31
|
+
waiter.callback { |r| remove_waiter correlation_id }
|
32
|
+
waiter.errback { |r| remove_waiter correlation_id }
|
33
|
+
waiter
|
34
|
+
end
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
end
|
36
|
+
def remove_waiter(correlation_id)
|
37
|
+
@waiters.delete correlation_id
|
40
38
|
end
|
41
39
|
end
|
data/lib/combi/service.rb
CHANGED
@@ -1,54 +1,50 @@
|
|
1
|
-
module Combi
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
self
|
10
|
-
end
|
1
|
+
module Combi::Service
|
2
|
+
def setup(service_bus, context)
|
3
|
+
context ||= {}
|
4
|
+
context[:service_bus] = service_bus
|
5
|
+
setup_context(context)
|
6
|
+
setup_services
|
7
|
+
self
|
8
|
+
end
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
10
|
+
def setup_context(context)
|
11
|
+
@context = context
|
12
|
+
@context.keys.each do |context_var|
|
13
|
+
define_singleton_method context_var do
|
14
|
+
@context[context_var]
|
18
15
|
end
|
19
16
|
end
|
17
|
+
end
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
def no_response
|
25
|
-
nil
|
26
|
-
end
|
19
|
+
def setup_services
|
20
|
+
end
|
27
21
|
|
28
|
-
|
29
|
-
|
30
|
-
|
22
|
+
def no_response
|
23
|
+
nil
|
24
|
+
end
|
31
25
|
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
def async_response(&block)
|
27
|
+
lambda &block
|
28
|
+
end
|
35
29
|
|
36
|
-
|
37
|
-
|
38
|
-
|
30
|
+
def actions
|
31
|
+
[]
|
32
|
+
end
|
39
33
|
|
40
|
-
|
41
|
-
|
42
|
-
|
34
|
+
def remote_methods
|
35
|
+
@_REMOTE_METHODS ||= public_methods(false) - Combi::Service.public_instance_methods
|
36
|
+
end
|
43
37
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
38
|
+
def service_bus
|
39
|
+
@service_bus
|
40
|
+
end
|
48
41
|
|
49
|
-
|
50
|
-
|
51
|
-
|
42
|
+
def enable(*services, &block)
|
43
|
+
service_bus.enable(services)
|
44
|
+
yield block if block_given?
|
45
|
+
end
|
52
46
|
|
47
|
+
def to_s
|
48
|
+
@_TO_S ||= "#{self.class.name}"
|
53
49
|
end
|
54
50
|
end
|
data/lib/combi/service_bus.rb
CHANGED
@@ -1,31 +1,28 @@
|
|
1
|
-
|
2
|
-
class
|
3
|
-
|
4
|
-
@@buses = {}
|
1
|
+
class Combi::ServiceBus
|
2
|
+
class << self
|
3
|
+
@@buses = {}
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
def for(kind, options = {})
|
6
|
+
@@buses[kind] ||= init_for(kind, options)
|
7
|
+
end
|
9
8
|
|
10
|
-
|
11
|
-
|
9
|
+
def init_for(kind, options)
|
10
|
+
require 'combi/buses/bus'
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
12
|
+
case kind
|
13
|
+
when :in_process
|
14
|
+
require 'combi/buses/in_process'
|
15
|
+
Combi::InProcess.new(options)
|
16
|
+
when :queue
|
17
|
+
require 'combi/buses/queue'
|
18
|
+
Combi::Queue.new(options)
|
19
|
+
when :web_socket
|
20
|
+
require 'combi/buses/web_socket'
|
21
|
+
Combi::WebSocket.new(options)
|
22
|
+
when :http
|
23
|
+
require 'combi/buses/http'
|
24
|
+
Combi::Http.new(options)
|
27
25
|
end
|
28
26
|
end
|
29
|
-
|
30
27
|
end
|
31
28
|
end
|
data/lib/combi/version.rb
CHANGED
@@ -28,11 +28,7 @@ describe 'Combi::Bus' do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
Given(:path) { 'module/remote' }
|
31
|
-
When { bus.add_service service_definition
|
32
|
-
puts bus.routes.inspect
|
33
|
-
puts bus.routes[path].inspect
|
34
|
-
puts bus.routes.keys.inspect
|
35
|
-
}
|
31
|
+
When { bus.add_service service_definition }
|
36
32
|
Then { bus.routes.keys.length == 1 }
|
37
33
|
And { bus.routes[path].is_a? service_definition }
|
38
34
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'singleton'
|
2
2
|
require 'socket'
|
3
3
|
require 'timeout'
|
4
|
+
require 'combi'
|
4
5
|
# Uses docker to start a server
|
5
6
|
class RabbitmqServer
|
6
7
|
include Singleton
|
@@ -11,9 +12,9 @@ class RabbitmqServer
|
|
11
12
|
def start!
|
12
13
|
needs_to_start = !container_running?
|
13
14
|
if needs_to_start
|
14
|
-
|
15
|
+
Combi.logger.debug {"Starting new Rabbitmq container"}
|
15
16
|
system "docker run -d -P -e RABBITMQ_PASS=#{PASSWORD} --name #{NAME} tutum/rabbitmq"
|
16
|
-
|
17
|
+
Combi.logger.debug {"RABBITMQ STARTING"}
|
17
18
|
end
|
18
19
|
start_forwarder!
|
19
20
|
is_port_open?('localhost', port)
|
@@ -32,11 +33,11 @@ class RabbitmqServer
|
|
32
33
|
return if @_command_running ||= `ps`.include?(command)
|
33
34
|
@forwarder_pid = Process.spawn command
|
34
35
|
#Process.detach @forwarder_pid
|
35
|
-
|
36
|
+
Combi.logger.debug {"starting forwarder pid: #{@forwarder_pid}"}
|
36
37
|
end
|
37
38
|
|
38
39
|
def stop_forwarder!
|
39
|
-
|
40
|
+
Combi.logger.debug {"stopping forwarder pid #{@forwarder_pid}"}
|
40
41
|
Process.kill 'TERM', @forwarder_pid if @forwarder_pid
|
41
42
|
rescue Error::ESRCH => e
|
42
43
|
# the forwarder process has already died
|
@@ -48,7 +49,7 @@ class RabbitmqServer
|
|
48
49
|
if port_match
|
49
50
|
return port_match[1].to_i
|
50
51
|
else
|
51
|
-
|
52
|
+
Combi.logger.info {"Container not running yet, sleeping"}
|
52
53
|
sleep 0.2
|
53
54
|
port
|
54
55
|
end
|
@@ -63,14 +64,13 @@ class RabbitmqServer
|
|
63
64
|
s.close
|
64
65
|
return true
|
65
66
|
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
66
|
-
puts "conn error to #{service}"
|
67
67
|
sleep 1
|
68
|
-
|
68
|
+
Combi.logger.info {"\tretrying connection to #{service}"}
|
69
69
|
retry
|
70
70
|
end
|
71
71
|
end
|
72
72
|
rescue Timeout::Error
|
73
|
-
|
73
|
+
Combi.logger.error {"Cannot connect to RABBIT server after #{timeout} seconds"}
|
74
74
|
end
|
75
75
|
|
76
76
|
return false
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: combi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- German Del Zotto
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-07-
|
12
|
+
date: 2014-07-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: yajl-ruby
|