eventhub-processor 0.2.1 → 0.2.3

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.
@@ -1,89 +1,89 @@
1
- require 'logger'
2
-
3
- # format adaptation
4
- class Logger
5
- class Formatter
6
- def call(severity, time, progname, msg)
7
- time_in_string = "#{time.strftime("%Y-%m-%d %H:%M:%S")}.#{"%04d" % (time.usec/100)}"
8
- [time_in_string,Process.pid,severity,msg].join("\t") + "\n"
9
- end
10
- end
11
-
12
- end
13
-
14
-
15
- module EventHub
16
-
17
- class MultiLogger
18
-
19
- MAX_EXCEPTIONS_FILES = 500
20
-
21
- attr_accessor :folder, :devices
22
-
23
- def initialize(folder=nil)
24
- @folder_base = folder || Dir.pwd
25
- @folder_base.chomp!('/')
26
- @folder = [@folder_base,'logs'].join('/')
27
- @folder_exceptions = [@folder_base,'exceptions'].join('/')
28
-
29
- @devices = []
30
-
31
- FileUtils.makedirs(@folder)
32
- end
33
-
34
- def add_device(device)
35
- @devices << device
36
- end
37
-
38
- def save_detailed_error(feedback,message=nil)
39
- time = Time.now
40
- stamp = "#{time.strftime("%Y%m%d_%H%M%S")}_#{"%03d" % (time.usec/1000)}"
41
- filename = "#{stamp}.log"
42
-
43
- FileUtils.makedirs(@folder_exceptions)
44
-
45
- # check max exception log files
46
- exception_files = Dir.glob(@folder_exceptions + '/*.log')
47
- if exception_files.size > MAX_EXCEPTIONS_FILES
48
- exception_files.reverse[MAX_EXCEPTIONS_FILES..-1].each do |file|
49
- begin
50
- File.delete(file)
51
- File.delete(File.dirname(file) + '/' + File.basename(file,".*") + '.msg.raw')
52
- rescue
53
- end
54
- end
55
- end
56
-
57
- File.open("#{@folder_exceptions}/#{filename}","w") do |output|
58
- output.write("#{feedback}\n\n")
59
- output.write("Exception: #{feedback.class.to_s}\n\n")
60
- output.write("Call Stack:\n")
61
- feedback.backtrace.each do |line|
62
- output.write("#{line}\n")
63
- end
64
- end
65
-
66
- # save message if provided
67
- if message
68
- File.open("#{@folder_exceptions}/#{stamp}.msg.raw","wb") do |output|
69
- output.write(message)
70
- end
71
- end
72
-
73
- return stamp
74
- end
75
-
76
- %w(log debug info warn error).each do |m|
77
- define_method(m) do |*args|
78
- @devices.map { |d| d.send(m, *args) }
79
- end
80
- end
81
-
82
- end
83
-
84
- end
85
-
86
-
87
-
88
-
89
-
1
+ require 'logger'
2
+
3
+ # format adaptation
4
+ class Logger
5
+ class Formatter
6
+ def call(severity, time, progname, msg)
7
+ time_in_string = "#{time.strftime("%Y-%m-%d %H:%M:%S")}.#{"%04d" % (time.usec/100)}"
8
+ [time_in_string,Process.pid,severity,msg].join("\t") + "\n"
9
+ end
10
+ end
11
+
12
+ end
13
+
14
+
15
+ module EventHub
16
+
17
+ class MultiLogger
18
+
19
+ MAX_EXCEPTIONS_FILES = 500
20
+
21
+ attr_accessor :folder, :devices
22
+
23
+ def initialize(folder=nil)
24
+ @folder_base = folder || Dir.pwd
25
+ @folder_base.chomp!('/')
26
+ @folder = [@folder_base,'logs'].join('/')
27
+ @folder_exceptions = [@folder_base,'exceptions'].join('/')
28
+
29
+ @devices = []
30
+
31
+ FileUtils.makedirs(@folder)
32
+ end
33
+
34
+ def add_device(device)
35
+ @devices << device
36
+ end
37
+
38
+ def save_detailed_error(feedback,message=nil)
39
+ time = Time.now
40
+ stamp = "#{time.strftime("%Y%m%d_%H%M%S")}_#{"%03d" % (time.usec/1000)}"
41
+ filename = "#{stamp}.log"
42
+
43
+ FileUtils.makedirs(@folder_exceptions)
44
+
45
+ # check max exception log files
46
+ exception_files = Dir.glob(@folder_exceptions + '/*.log')
47
+ if exception_files.size > MAX_EXCEPTIONS_FILES
48
+ exception_files.reverse[MAX_EXCEPTIONS_FILES..-1].each do |file|
49
+ begin
50
+ File.delete(file)
51
+ File.delete(File.dirname(file) + '/' + File.basename(file,".*") + '.msg.raw')
52
+ rescue
53
+ end
54
+ end
55
+ end
56
+
57
+ File.open("#{@folder_exceptions}/#{filename}","w") do |output|
58
+ output.write("#{feedback}\n\n")
59
+ output.write("Exception: #{feedback.class.to_s}\n\n")
60
+ output.write("Call Stack:\n")
61
+ feedback.backtrace.each do |line|
62
+ output.write("#{line}\n")
63
+ end
64
+ end
65
+
66
+ # save message if provided
67
+ if message
68
+ File.open("#{@folder_exceptions}/#{stamp}.msg.raw","wb") do |output|
69
+ output.write(message)
70
+ end
71
+ end
72
+
73
+ return stamp
74
+ end
75
+
76
+ %w(log debug info warn error).each do |m|
77
+ define_method(m) do |*args|
78
+ @devices.map { |d| d.send(m, *args) }
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+
86
+
87
+
88
+
89
+
@@ -1,307 +1,307 @@
1
- module EventHub
2
- class Processor
3
-
4
- attr_accessor :name, :folder
5
-
6
- include Helper
7
-
8
- def version
9
- "1.0.0"
10
- end
11
-
12
- def initialize(name=nil)
13
- @name = name || class_to_array(self.class)[1..-1].join(".")
14
- @folder = Dir.pwd
15
-
16
- # Variables used for heartbeat statistics
17
- @started = Time.now
18
- @messages_successful = 0
19
- @messages_unsuccessful = 0
20
- @messages_average_size = 0
21
- @messages_average_process_time = 0
22
- @first_message = true
23
-
24
- @channel_receiver = nil
25
- @channel_sender = nil
26
- @restart = true
27
- end
28
-
29
- def configuration
30
- EventHub::Configuration.instance.data
31
- end
32
-
33
- def server_host
34
- configuration.get('server.host') || 'localhost'
35
- end
36
-
37
- def server_user
38
- configuration.get('server.user') || 'admin'
39
- end
40
-
41
- def server_password
42
- configuration.get('server.password') || 'admin'
43
- end
44
-
45
- def server_management_port
46
- configuration.get('server.management_port') || 15672
47
- end
48
-
49
- def server_vhost
50
- configuration.get('server.vhost') || 'event_hub'
51
- end
52
-
53
- def connection_settings
54
- { user: server_user, password: server_password, host: server_host, vhost: server_vhost }
55
- end
56
-
57
- def listener_queue
58
- configuration.get('processor.listener_queue') || 'undefined_listener_queue'
59
- end
60
-
61
- def watchdog_cycle_in_s
62
- configuration.get('processor.watchdog_cycle_is_s') || 15
63
- end
64
-
65
- def restart_in_s
66
- configuration.get('processor.restart_in_s') || 15
67
- end
68
-
69
- def heartbeat_cycle_in_s
70
- configuration.get('processor.heartbeat_cycle_in_s') || 300
71
- end
72
-
73
- def start(detached=false)
74
- daemonize if detached
75
-
76
- EventHub.logger.info("Processor [#{@name}] base folder [#{@folder}]")
77
-
78
- while @restart
79
-
80
- begin
81
- AMQP.start(self.connection_settings) do |connection, open_ok|
82
-
83
- @connection = connection
84
-
85
- # deal with tcp connection issues
86
- @connection.on_tcp_connection_loss do |conn, settings|
87
- EventHub.logger.warn("Processor lost tcp connection. Trying to restart in #{self.restart_in_s} seconds...")
88
- stop_processor(true)
89
- end
90
-
91
- # create channel
92
- @channel_receiver = AMQP::Channel.new(@connection, prefetch: 1)
93
-
94
- # connect to queue
95
- @queue = @channel_receiver.queue(self.listener_queue, durable: true, auto_delete: false)
96
-
97
- # subscribe to queue
98
- @queue.subscribe(:ack => true) do |metadata, payload|
99
- begin
100
- start_stamp = Time.now
101
- messages_to_send = []
102
-
103
- # try to convert to Evenhub message
104
- message = Message.from_json(payload)
105
- EventHub.logger.info("-> #{message.to_s}")
106
-
107
- if message.status_code == STATUS_INVALID
108
- messages_to_send << message
109
- EventHub.logger.info("-> #{message.to_s} => Put to queue [#{EH_X_INBOUND}].")
110
- else
111
- # pass received message to handler or dervied handler
112
- messages_to_send = Array(handle_message(message))
113
- end
114
-
115
- # forward invalid or returned messages to dispatcher
116
- messages_to_send.each do |message|
117
- send_message(message)
118
- end
119
- @channel_receiver.acknowledge(metadata.delivery_tag)
120
-
121
- # collect statistics for the heartbeat
122
- @messages_successful += 1
123
- if @first_message
124
- @messages_average_process_time = Time.now - start_stamp
125
- @messages_average_size = payload.size
126
- @first_message = false
127
- else
128
- @messages_average_process_time = (@messages_average_process_time + (Time.now - start_stamp))/2.0
129
- @messages_average_size = (@messages_average_size + payload.size) / 2.0
130
- end
131
-
132
- rescue => e
133
- @channel_receiver.reject(metadata.delivery_tag,false)
134
- @messages_unsuccessful += 1
135
- EventHub.logger.error("Unexpected exception in handle_message method: #{e}. Message dead lettered.")
136
- EventHub.logger.save_detailed_error(e)
137
- end
138
- end
139
-
140
- EventHub.logger.info("Processor [#{@name}] is listening to vhost [#{self.server_vhost}], queue [#{self.listener_queue}]")
141
-
142
- # Singnal Listening
143
- Signal.trap("TERM") {stop_processor}
144
- Signal.trap("INT") {stop_processor}
145
-
146
- # post_start is a custom post start routing to be overwritten
147
- post_start
148
-
149
- # Various timers
150
- EventMachine.add_timer(@watchdog_cycle_in_s) { watchdog }
151
-
152
- heartbeat
153
- end
154
- rescue => e
155
- Signal.trap("TERM") { stop_processor }
156
- Signal.trap("INT") { stop_processor }
157
-
158
- id = EventHub.logger.save_detailed_error(e)
159
- EventHub.logger.error("Unexpected exception: #{e}, see => #{id}. Trying to restart in #{self.restart_in_s} seconds...")
160
-
161
- sleep_break self.restart_in_s
162
- end
163
-
164
- end # while
165
-
166
- # post_start is a custom post start routing to be overwritten
167
- post_stop
168
-
169
- EventHub.logger.info("Processor [#{@name}] has been stopped")
170
- ensure
171
- # remove pid file
172
- begin
173
- File.delete("#{@folder}/pids/#{@name}.pid")
174
- rescue
175
- # ignore exceptions here
176
- end
177
- end
178
-
179
- def handle_message(metadata,payload)
180
- raise "Please implement method in derived class"
181
- end
182
-
183
- def watchdog
184
- begin
185
- response = RestClient.get "http://#{self.server_user}:#{self.server_password}@#{self.server_host}:#{self.server_management_port}/api/queues/#{self.server_vhost}/#{self.listener_queue}/bindings", { :content_type => :json}
186
- data = JSON.parse(response.body)
187
-
188
- if response.code != 200
189
- EventHub.logger.warn("Watchdog: Server did not answered properly. Trying to restart in #{self.restart_in_s} seconds...")
190
- EventMachine.add_timer(self.restart_in_s) { stop_processor(true) }
191
- elsif data.size == 0
192
- EventHub.logger.warn("Watchdog: Something is wrong with the vhost, queue, and/or bindings. Trying to restart in #{self.restart_in_s} seconds...")
193
- EventMachine.add_timer(self.restart_in_s) { stop_processor(true) }
194
- # does it make sence ? Needs maybe more checks in future
195
- else
196
- # Watchdog is happy :-)
197
- # add timer for next check
198
- EventMachine.add_timer(self.watchdog_cycle_in_s) { watchdog }
199
- end
200
-
201
- rescue => e
202
- EventHub.logger.error("Watchdog: Unexpected exception: #{e}. Trying to restart in #{self.restart_in_s} seconds...")
203
- stop_processor
204
- end
205
- end
206
-
207
- def heartbeat
208
- message = Message.new
209
- message.origin_module_id = @name
210
- message.origin_type = "processor"
211
- message.origin_site_id = 'global'
212
-
213
- message.process_name = 'event_hub.heartbeat'
214
-
215
- now = Time.now
216
- message.body = {
217
- version: self.version,
218
- heartbeat: {
219
- started: now_stamp(@started),
220
- stamp_last_beat: now_stamp(now),
221
- uptime: duration(now-@started),
222
- heartbeat_cycle_in_s: self.heartbeat_cycle_in_s,
223
- served_queues: [self.listener_queue],
224
- host: get_host,
225
- ip_adresses: get_ip_adresses,
226
- messages: {
227
- total: @messages_successful+@messages_unsuccessful,
228
- successful: @messages_successful,
229
- unsuccessful: @messages_unsuccessful,
230
- average_size: @messages_average_size,
231
- average_process_time: @messages_average_process_time
232
- }
233
- }
234
- }
235
-
236
- # send heartbeat message
237
- send_message(message)
238
-
239
- EventMachine.add_timer(self.heartbeat_cycle_in_s) { heartbeat }
240
-
241
- end
242
-
243
- # send message
244
- def send_message(message,exchange_name=EH_X_INBOUND)
245
-
246
- if @channel_sender.nil? || !@channel_sender.open?
247
- @channel_sender = AMQP::Channel.new(@connection, prefetch: 1)
248
-
249
- # use publisher confirm
250
- @channel_sender.confirm_select
251
-
252
- # @channel.on_error { |ch, channel_close| EventHub.logger.error "Oops! a channel-level exception: #{channel_close.reply_text}" }
253
- # @channel.on_ack { |basic_ack| EventHub.logger.info "Received basic_ack: multiple = #{basic_ack.multiple}, delivery_tag = #{basic_ack.delivery_tag}" }
254
- end
255
-
256
- exchange = @channel_sender.direct(exchange_name, :durable => true, :auto_delete => false)
257
- exchange.publish(message.to_json, :persistent => true)
258
- end
259
-
260
- def sleep_break( seconds ) # breaks after n seconds or after interrupt
261
- while (seconds > 0)
262
- sleep(1)
263
- seconds -= 1
264
- break unless @restart
265
- end
266
- end
267
-
268
- private
269
-
270
- def stop_processor(restart=false)
271
- @restart = restart
272
-
273
- # close channels
274
- [@channel_receiver,@channel_sender].each do |channel|
275
- if channel
276
- channel.close if channel.open?
277
- end
278
- end
279
-
280
- # stop connection and event loop
281
- if @connection
282
- @connection.disconnect if @connection.connected?
283
- EventMachine.stop if EventMachine.reactor_running?
284
- end
285
- end
286
-
287
- def daemonize
288
- EventHub.logger.info("Processor [#{@name}] is going to start as daemon")
289
-
290
- # daemonize
291
- Process.daemon
292
-
293
- # write daemon pid
294
- pids_folder = @folder + "/pids"
295
- FileUtils.makedirs(pids_folder)
296
- IO.write("#{pids_folder}/#{@name}.pid",Process.pid.to_s)
297
- end
298
-
299
- def post_start
300
- # method which can be overwritten to call a code sequence after reactor start
301
- end
302
-
303
- def post_stop
304
- end
305
-
306
- end
1
+ module EventHub
2
+ class Processor
3
+
4
+ attr_accessor :name, :folder
5
+
6
+ include Helper
7
+
8
+ def version
9
+ "1.0.0"
10
+ end
11
+
12
+ def initialize(name=nil)
13
+ @name = name || class_to_array(self.class)[1..-1].join(".")
14
+ @folder = Dir.pwd
15
+
16
+ # Variables used for heartbeat statistics
17
+ @started = Time.now
18
+ @messages_successful = 0
19
+ @messages_unsuccessful = 0
20
+ @messages_average_size = 0
21
+ @messages_average_process_time = 0
22
+ @first_message = true
23
+
24
+ @channel_receiver = nil
25
+ @channel_sender = nil
26
+ @restart = true
27
+ end
28
+
29
+ def configuration
30
+ EventHub::Configuration.instance.data
31
+ end
32
+
33
+ def server_host
34
+ configuration.get('server.host') || 'localhost'
35
+ end
36
+
37
+ def server_user
38
+ configuration.get('server.user') || 'admin'
39
+ end
40
+
41
+ def server_password
42
+ configuration.get('server.password') || 'admin'
43
+ end
44
+
45
+ def server_management_port
46
+ configuration.get('server.management_port') || 15672
47
+ end
48
+
49
+ def server_vhost
50
+ configuration.get('server.vhost') || 'event_hub'
51
+ end
52
+
53
+ def connection_settings
54
+ { user: server_user, password: server_password, host: server_host, vhost: server_vhost }
55
+ end
56
+
57
+ def listener_queue
58
+ configuration.get('processor.listener_queue') || 'undefined_listener_queue'
59
+ end
60
+
61
+ def watchdog_cycle_in_s
62
+ configuration.get('processor.watchdog_cycle_is_s') || 15
63
+ end
64
+
65
+ def restart_in_s
66
+ configuration.get('processor.restart_in_s') || 15
67
+ end
68
+
69
+ def heartbeat_cycle_in_s
70
+ configuration.get('processor.heartbeat_cycle_in_s') || 300
71
+ end
72
+
73
+ def start(detached=false)
74
+ daemonize if detached
75
+
76
+ EventHub.logger.info("Processor [#{@name}] base folder [#{@folder}]")
77
+
78
+ while @restart
79
+
80
+ begin
81
+ AMQP.start(self.connection_settings) do |connection, open_ok|
82
+
83
+ @connection = connection
84
+
85
+ # deal with tcp connection issues
86
+ @connection.on_tcp_connection_loss do |conn, settings|
87
+ EventHub.logger.warn("Processor lost tcp connection. Trying to restart in #{self.restart_in_s} seconds...")
88
+ stop_processor(true)
89
+ end
90
+
91
+ # create channel
92
+ @channel_receiver = AMQP::Channel.new(@connection, prefetch: 1)
93
+
94
+ # connect to queue
95
+ @queue = @channel_receiver.queue(self.listener_queue, durable: true, auto_delete: false)
96
+
97
+ # subscribe to queue
98
+ @queue.subscribe(:ack => true) do |metadata, payload|
99
+ begin
100
+ start_stamp = Time.now
101
+ messages_to_send = []
102
+
103
+ # try to convert to Evenhub message
104
+ message = Message.from_json(payload)
105
+ EventHub.logger.info("-> #{message.to_s}")
106
+
107
+ if message.status_code == STATUS_INVALID
108
+ messages_to_send << message
109
+ EventHub.logger.info("-> #{message.to_s} => Put to queue [#{EH_X_INBOUND}].")
110
+ else
111
+ # pass received message to handler or dervied handler
112
+ messages_to_send = Array(handle_message(message))
113
+ end
114
+
115
+ # forward invalid or returned messages to dispatcher
116
+ messages_to_send.each do |message|
117
+ send_message(message)
118
+ end
119
+ @channel_receiver.acknowledge(metadata.delivery_tag)
120
+
121
+ # collect statistics for the heartbeat
122
+ @messages_successful += 1
123
+ if @first_message
124
+ @messages_average_process_time = Time.now - start_stamp
125
+ @messages_average_size = payload.size
126
+ @first_message = false
127
+ else
128
+ @messages_average_process_time = (@messages_average_process_time + (Time.now - start_stamp))/2.0
129
+ @messages_average_size = (@messages_average_size + payload.size) / 2.0
130
+ end
131
+
132
+ rescue => e
133
+ @channel_receiver.reject(metadata.delivery_tag,false)
134
+ @messages_unsuccessful += 1
135
+ EventHub.logger.error("Unexpected exception in handle_message method: #{e}. Message dead lettered.")
136
+ EventHub.logger.save_detailed_error(e)
137
+ end
138
+ end
139
+
140
+ EventHub.logger.info("Processor [#{@name}] is listening to vhost [#{self.server_vhost}], queue [#{self.listener_queue}]")
141
+
142
+ # Singnal Listening
143
+ Signal.trap("TERM") {stop_processor}
144
+ Signal.trap("INT") {stop_processor}
145
+
146
+ # post_start is a custom post start routing to be overwritten
147
+ post_start
148
+
149
+ # Various timers
150
+ EventMachine.add_timer(@watchdog_cycle_in_s) { watchdog }
151
+
152
+ heartbeat
153
+ end
154
+ rescue => e
155
+ Signal.trap("TERM") { stop_processor }
156
+ Signal.trap("INT") { stop_processor }
157
+
158
+ id = EventHub.logger.save_detailed_error(e)
159
+ EventHub.logger.error("Unexpected exception: #{e}, see => #{id}. Trying to restart in #{self.restart_in_s} seconds...")
160
+
161
+ sleep_break self.restart_in_s
162
+ end
163
+
164
+ end # while
165
+
166
+ # post_start is a custom post start routing to be overwritten
167
+ post_stop
168
+
169
+ EventHub.logger.info("Processor [#{@name}] has been stopped")
170
+ ensure
171
+ # remove pid file
172
+ begin
173
+ File.delete("#{@folder}/pids/#{@name}.pid")
174
+ rescue
175
+ # ignore exceptions here
176
+ end
177
+ end
178
+
179
+ def handle_message(metadata,payload)
180
+ raise "Please implement method in derived class"
181
+ end
182
+
183
+ def watchdog
184
+ begin
185
+ response = RestClient.get "http://#{self.server_user}:#{self.server_password}@#{self.server_host}:#{self.server_management_port}/api/queues/#{self.server_vhost}/#{self.listener_queue}/bindings", { :content_type => :json}
186
+ data = JSON.parse(response.body)
187
+
188
+ if response.code != 200
189
+ EventHub.logger.warn("Watchdog: Server did not answered properly. Trying to restart in #{self.restart_in_s} seconds...")
190
+ EventMachine.add_timer(self.restart_in_s) { stop_processor(true) }
191
+ elsif data.size == 0
192
+ EventHub.logger.warn("Watchdog: Something is wrong with the vhost, queue, and/or bindings. Trying to restart in #{self.restart_in_s} seconds...")
193
+ EventMachine.add_timer(self.restart_in_s) { stop_processor(true) }
194
+ # does it make sence ? Needs maybe more checks in future
195
+ else
196
+ # Watchdog is happy :-)
197
+ # add timer for next check
198
+ EventMachine.add_timer(self.watchdog_cycle_in_s) { watchdog }
199
+ end
200
+
201
+ rescue => e
202
+ EventHub.logger.error("Watchdog: Unexpected exception: #{e}. Trying to restart in #{self.restart_in_s} seconds...")
203
+ stop_processor
204
+ end
205
+ end
206
+
207
+ def heartbeat
208
+ message = Message.new
209
+ message.origin_module_id = @name
210
+ message.origin_type = "processor"
211
+ message.origin_site_id = 'global'
212
+
213
+ message.process_name = 'event_hub.heartbeat'
214
+
215
+ now = Time.now
216
+ message.body = {
217
+ version: self.version,
218
+ heartbeat: {
219
+ started: now_stamp(@started),
220
+ stamp_last_beat: now_stamp(now),
221
+ uptime: duration(now-@started),
222
+ heartbeat_cycle_in_s: self.heartbeat_cycle_in_s,
223
+ served_queues: [self.listener_queue],
224
+ host: get_host,
225
+ ip_adresses: get_ip_adresses,
226
+ messages: {
227
+ total: @messages_successful+@messages_unsuccessful,
228
+ successful: @messages_successful,
229
+ unsuccessful: @messages_unsuccessful,
230
+ average_size: @messages_average_size,
231
+ average_process_time: @messages_average_process_time
232
+ }
233
+ }
234
+ }
235
+
236
+ # send heartbeat message
237
+ send_message(message)
238
+
239
+ EventMachine.add_timer(self.heartbeat_cycle_in_s) { heartbeat }
240
+
241
+ end
242
+
243
+ # send message
244
+ def send_message(message,exchange_name=EH_X_INBOUND)
245
+
246
+ if @channel_sender.nil? || !@channel_sender.open?
247
+ @channel_sender = AMQP::Channel.new(@connection, prefetch: 1)
248
+
249
+ # use publisher confirm
250
+ @channel_sender.confirm_select
251
+
252
+ # @channel.on_error { |ch, channel_close| EventHub.logger.error "Oops! a channel-level exception: #{channel_close.reply_text}" }
253
+ # @channel.on_ack { |basic_ack| EventHub.logger.info "Received basic_ack: multiple = #{basic_ack.multiple}, delivery_tag = #{basic_ack.delivery_tag}" }
254
+ end
255
+
256
+ exchange = @channel_sender.direct(exchange_name, :durable => true, :auto_delete => false)
257
+ exchange.publish(message.to_json, :persistent => true)
258
+ end
259
+
260
+ def sleep_break( seconds ) # breaks after n seconds or after interrupt
261
+ while (seconds > 0)
262
+ sleep(1)
263
+ seconds -= 1
264
+ break unless @restart
265
+ end
266
+ end
267
+
268
+ private
269
+
270
+ def stop_processor(restart=false)
271
+ @restart = restart
272
+
273
+ # close channels
274
+ [@channel_receiver,@channel_sender].each do |channel|
275
+ if channel
276
+ channel.close if channel.open?
277
+ end
278
+ end
279
+
280
+ # stop connection and event loop
281
+ if @connection
282
+ @connection.disconnect if @connection.connected?
283
+ EventMachine.stop if EventMachine.reactor_running?
284
+ end
285
+ end
286
+
287
+ def daemonize
288
+ EventHub.logger.info("Processor [#{@name}] is going to start as daemon")
289
+
290
+ # daemonize
291
+ Process.daemon
292
+
293
+ # write daemon pid
294
+ pids_folder = @folder + "/pids"
295
+ FileUtils.makedirs(pids_folder)
296
+ IO.write("#{pids_folder}/#{@name}.pid",Process.pid.to_s)
297
+ end
298
+
299
+ def post_start
300
+ # method which can be overwritten to call a code sequence after reactor start
301
+ end
302
+
303
+ def post_stop
304
+ end
305
+
306
+ end
307
307
  end