process_handler 1.1.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6e119788704709faa74d7d32dcd6f51ce7855cca
4
- data.tar.gz: b11089474652313aa5ab9b011b2faf98fb3c5675
3
+ metadata.gz: 503d8ce446eeb4caa121a37d828f72c7662ac37d
4
+ data.tar.gz: fb470e66c0e819f29ccc74238ece33fe8cb4ea00
5
5
  SHA512:
6
- metadata.gz: ecf3ec60ff2258b482b4fba84ab246e53863972348393334c17baf7595b596c1c0ec94893fec5661e2bc374e28cd15223ac53ea49e4aea5e3db747f3bd7ea86a
7
- data.tar.gz: 39e37e9e8c3e3d6fe0efcb76bb7b9b28f0ee92b467f5b1f51628ed27d658e6b6df10f520c7de039c68758937b887d04e118c8932e559e2c969f372a46e78e355
6
+ metadata.gz: e509844d303791e07770096198abb40a9dae45c9de590b96ca38b96c3d896d03b52e0d426bba7ea4d3b3b542363bd91f8880d881c1272a8e22f2177d98161590
7
+ data.tar.gz: 7154af8b659b52b3aca64c12011dc92d7599115bcebadd769eb1fd79f9e1a9b96fc14d1014b410a30be3efb29d510950201c3b8525a45d62c133272069389bb7
data/README.md CHANGED
@@ -12,8 +12,14 @@ Example of using pivot process:
12
12
  ```ruby
13
13
  service = MyService.new
14
14
  freddy = Freddy.new
15
+ statsd = Statsd.new
16
+ logger = Logasm.build('my-app', {stdout: {level: :debug}})
15
17
 
16
- process = Salemove::ProcessHandler::PivotProcess.new(freddy)
18
+ process = Salemove::ProcessHandler::PivotProcess.new(
19
+ freddy: freddy,
20
+ logger: logger,
21
+ statsd: statsd
22
+ )
17
23
  process.spawn(service)
18
24
  ```
19
25
 
@@ -1,4 +1,3 @@
1
- require 'logger'
2
1
  require 'benchmark'
3
2
  require 'securerandom'
4
3
  require_relative 'process_monitor'
@@ -9,17 +8,10 @@ module Salemove
9
8
  class PivotProcess
10
9
 
11
10
  DEFAULT_FULFILLABLE_TIMEOUT = 3
11
+ DEFAULT_EXECUTION_TIME_KEY = 'service.execution_time'.freeze
12
12
 
13
13
  attr_reader :process_monitor, :exception_notifier
14
14
 
15
- def self.logger
16
- @logger ||= Logger.new(STDOUT).tap { |l| l.level = Logger::INFO }
17
- end
18
-
19
- def self.logger=(logger)
20
- @logger = logger
21
- end
22
-
23
15
  def self.tracing_supported?
24
16
  defined?(Freddy) &&
25
17
  Freddy.respond_to?(:trace) &&
@@ -34,13 +26,22 @@ module Salemove
34
26
  end
35
27
  end
36
28
 
37
- def initialize(freddy,
29
+ def initialize(freddy:,
30
+ logger:,
31
+ statsd:,
38
32
  notifier: nil,
39
33
  notifier_factory: NotifierFactory,
40
34
  process_monitor: ProcessMonitor.new,
41
35
  process_name: 'Unknown process',
36
+ execution_time_key: DEFAULT_EXECUTION_TIME_KEY,
42
37
  exit_enforcer: nil)
43
38
  @freddy = freddy
39
+ @logger = logger
40
+ @benchmarker = Benchmarker.new(
41
+ statsd: statsd,
42
+ application: process_name,
43
+ execution_time_key: execution_time_key
44
+ )
44
45
  @process_monitor = process_monitor
45
46
  @exception_notifier = notifier_factory.get_notifier(process_name, notifier)
46
47
  # Needed for forcing exit from jruby with exit(0)
@@ -56,7 +57,15 @@ module Salemove
56
57
 
57
58
  def spawn_queue_threads(service)
58
59
  if service.class.const_defined?(:QUEUE)
59
- [ServiceSpawner.spawn(service, @freddy, @exception_notifier)]
60
+ [
61
+ ServiceSpawner.new(
62
+ service,
63
+ freddy: @freddy,
64
+ logger: @logger,
65
+ benchmarker: @benchmarker,
66
+ exception_notifier: @exception_notifier
67
+ ).spawn
68
+ ]
60
69
  else
61
70
  []
62
71
  end
@@ -65,7 +74,13 @@ module Salemove
65
74
  def spawn_tap_threads(service)
66
75
  if service.class.const_defined?(:TAPPED_QUEUES)
67
76
  service.class::TAPPED_QUEUES.map do |queue|
68
- spawner = TapServiceSpawner.new(service, @freddy, @exception_notifier)
77
+ spawner = TapServiceSpawner.new(
78
+ service,
79
+ freddy: @freddy,
80
+ logger: @logger,
81
+ benchmarker: @benchmarker,
82
+ exception_notifier: @exception_notifier
83
+ )
69
84
  spawner.spawn(queue)
70
85
  end
71
86
  else
@@ -75,18 +90,6 @@ module Salemove
75
90
 
76
91
  private
77
92
 
78
- def self.benchmark(input, &block)
79
- type = input[:type] if input.is_a?(Hash)
80
- result = nil
81
-
82
- bm = Benchmark.measure { result = block.call }
83
- if defined?(Logasm) && PivotProcess.logger.is_a?(Logasm)
84
- PivotProcess.logger.info "Execution time", {
85
- type: type, real: bm.real, user: bm.utime, system: bm.stime
86
- }.merge(PivotProcess.trace_information)
87
- end
88
- result
89
- end
90
93
 
91
94
  def wait_for_monitor
92
95
  sleep 1 while @process_monitor.running?
@@ -96,9 +99,11 @@ module Salemove
96
99
  end
97
100
 
98
101
  class TapServiceSpawner
99
- def initialize(service, freddy, exception_notifier)
102
+ def initialize(service, freddy:, logger:, benchmarker:, exception_notifier:)
100
103
  @service = service
101
104
  @freddy = freddy
105
+ @logger = logger
106
+ @benchmarker = benchmarker
102
107
  @exception_notifier = exception_notifier
103
108
  end
104
109
 
@@ -109,14 +114,14 @@ module Salemove
109
114
  end
110
115
 
111
116
  def delegate_to_service(input)
112
- PivotProcess.logger.info "Received request", PivotProcess.trace_information.merge(input)
113
- PivotProcess.benchmark(input) { @service.call(input) }
117
+ @logger.info 'Received request', PivotProcess.trace_information.merge(input)
118
+ @benchmarker.call(input) { @service.call(input) }
114
119
  rescue => exception
115
120
  handle_exception(exception, input)
116
121
  end
117
122
 
118
123
  def handle_exception(e, input)
119
- PivotProcess.logger.error(e.inspect + "\n" + e.backtrace.join("\n"), PivotProcess.trace_information)
124
+ @logger.error(e.inspect + "\n" + e.backtrace.join("\n"), PivotProcess.trace_information)
120
125
  if @exception_notifier
121
126
  @exception_notifier.notify_or_ignore(e, cgi_data: ENV.to_hash, parameters: input)
122
127
  end
@@ -126,13 +131,11 @@ module Salemove
126
131
  class ServiceSpawner
127
132
  PROCESSED_REQUEST_LOG_KEYS = [:error, :success]
128
133
 
129
- def self.spawn(service, freddy, exception_notifier)
130
- new(service, freddy, exception_notifier).spawn
131
- end
132
-
133
- def initialize(service, freddy, exception_notifier)
134
+ def initialize(service, freddy:, logger:, benchmarker:, exception_notifier:)
134
135
  @service = service
135
136
  @freddy = freddy
137
+ @logger = logger
138
+ @benchmarker = benchmarker
136
139
  @exception_notifier = exception_notifier
137
140
  end
138
141
 
@@ -159,7 +162,7 @@ module Salemove
159
162
  end
160
163
  end
161
164
  rescue Timeout::Error
162
- PivotProcess.logger.error "Fullfillable response was not fulfilled in #{timeout} seconds", input
165
+ @logger.error "Fullfillable response was not fulfilled in #{timeout} seconds", input
163
166
  handle_response(handler, success: false, error: "Fulfillable response was not fulfilled")
164
167
  end
165
168
 
@@ -172,7 +175,7 @@ module Salemove
172
175
  end
173
176
 
174
177
  def handle_request(input)
175
- PivotProcess.logger.info "Received request", PivotProcess.trace_information.merge(input)
178
+ @logger.info 'Received request', PivotProcess.trace_information.merge(input)
176
179
  if input.has_key?(:ping)
177
180
  { success: true, pong: 'pong' }
178
181
  else
@@ -183,7 +186,7 @@ module Salemove
183
186
  end
184
187
 
185
188
  def delegate_to_service(input)
186
- result = PivotProcess.benchmark(input) { @service.call(input) }
189
+ result = @benchmarker.call(input) { @service.call(input) }
187
190
  if !result.respond_to?(:fulfilled?)
188
191
  log_processed_request(input, result)
189
192
  end
@@ -197,17 +200,39 @@ module Salemove
197
200
  .merge(type: input[:type])
198
201
  .merge(PivotProcess.trace_information)
199
202
 
200
- PivotProcess.logger.info "Processed request", attributes
203
+ @logger.info 'Processed request', attributes
201
204
  end
202
205
 
203
206
  def handle_exception(e, input)
204
- PivotProcess.logger.error(e.inspect + "\n" + e.backtrace.join("\n"), PivotProcess.trace_information)
207
+ @logger.error(e.inspect + "\n" + e.backtrace.join("\n"), PivotProcess.trace_information)
205
208
  if @exception_notifier
206
209
  @exception_notifier.notify_or_ignore(e, cgi_data: ENV.to_hash, parameters: input)
207
210
  end
208
211
  { success: false, error: e.message }
209
212
  end
210
213
  end
214
+
215
+ class Benchmarker
216
+ def initialize(statsd:, application:, execution_time_key:)
217
+ @statsd = statsd
218
+ @application = application
219
+ @execution_time_key = execution_time_key
220
+ end
221
+
222
+ def call(input, &block)
223
+ type = input[:type] if input.is_a?(Hash)
224
+ result = nil
225
+
226
+ bm = Benchmark.measure { result = block.call }
227
+
228
+ @statsd.histogram(@execution_time_key, bm.real, tags: [
229
+ "application:#{@application}",
230
+ "type:#{type || 'unknown'}"
231
+ ])
232
+
233
+ result
234
+ end
235
+ end
211
236
  end
212
237
  end
213
238
  end
@@ -1,5 +1,5 @@
1
1
  module Salemove
2
2
  module ProcessHandler
3
- VERSION = '1.1.2'
3
+ VERSION = '2.0.0'
4
4
  end
5
5
  end
@@ -13,12 +13,17 @@ module Salemove
13
13
  end
14
14
  end
15
15
 
16
- class Messenger
16
+ class Freddy
17
17
  def respond_to(*)
18
18
  ResponderHandler.new
19
19
  end
20
20
  end
21
21
 
22
+ class DummyStatsd
23
+ def histogram(*)
24
+ end
25
+ end
26
+
22
27
  class ResponderHandler
23
28
  def shutdown
24
29
  end
@@ -28,8 +33,11 @@ module Salemove
28
33
  cron_process.schedule('0.5')
29
34
  cron_process.schedule('5', some: 'params')
30
35
 
31
- ProcessHandler::PivotProcess.logger = Logger.new('/dev/null')
32
- pivot_process = ProcessHandler::PivotProcess.new(Messenger.new)
36
+ pivot_process = ProcessHandler::PivotProcess.new(
37
+ freddy: Freddy.new,
38
+ logger: Logger.new('/dev/null'),
39
+ statsd: DummyStatsd.new
40
+ )
33
41
 
34
42
  ProcessHandler.start_composite do
35
43
  add cron_process, EchoResultService.new
@@ -5,13 +5,24 @@ require 'salemove/process_handler/pivot_process'
5
5
  describe ProcessHandler::PivotProcess do
6
6
  let(:monitor) { double('Monitor') }
7
7
  let(:freddy) { double('Freddy') }
8
+ let(:statsd) { spy('Statsd') }
8
9
  let(:handler) { double('Handler') }
9
10
  let(:thread) { double('Thread') }
10
- let(:process) { ProcessHandler::PivotProcess.new(freddy, process_params) }
11
- let(:process_params) {{ process_monitor: monitor , notifier_factory: notifier_factory}}
12
11
  let(:notifier_factory) { double('NotifierFactory') }
13
12
  let(:responder) { double(shutdown: true) }
14
13
  let(:logger) { Logasm.build('test-app', []) }
14
+ let(:application) { 'my-app' }
15
+
16
+ let(:process) do
17
+ ProcessHandler::PivotProcess.new(
18
+ freddy: freddy,
19
+ logger: logger,
20
+ statsd: statsd,
21
+ process_monitor: monitor,
22
+ process_name: application,
23
+ notifier_factory: notifier_factory
24
+ )
25
+ end
15
26
 
16
27
  def expect_monitor_to_behave
17
28
  expect(monitor).to receive(:start)
@@ -20,7 +31,6 @@ describe ProcessHandler::PivotProcess do
20
31
  end
21
32
 
22
33
  before do
23
- ProcessHandler::PivotProcess.logger = logger
24
34
  allow(notifier_factory).to receive(:get_notifier) { nil }
25
35
  expect_monitor_to_behave
26
36
  end
@@ -62,6 +72,15 @@ describe ProcessHandler::PivotProcess do
62
72
  subject()
63
73
  end
64
74
 
75
+ it 'records execution time' do
76
+ expect(statsd).to receive(:histogram)
77
+ .with(
78
+ 'service.execution_time',
79
+ instance_of(Float),
80
+ tags: ["application:#{application}", "type:unknown"]
81
+ )
82
+ subject()
83
+ end
65
84
  end
66
85
 
67
86
  describe 'when service responds with an error' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: process_handler
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SaleMove TechMovers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-11 00:00:00.000000000 Z
11
+ date: 2018-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: airbrake