process_handler 1.1.2 → 2.0.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 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