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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 503d8ce446eeb4caa121a37d828f72c7662ac37d
|
4
|
+
data.tar.gz: fb470e66c0e819f29ccc74238ece33fe8cb4ea00
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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(
|
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
|
-
[
|
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(
|
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
|
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
|
-
|
113
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
203
|
+
@logger.info 'Processed request', attributes
|
201
204
|
end
|
202
205
|
|
203
206
|
def handle_exception(e, input)
|
204
|
-
|
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
|
@@ -13,12 +13,17 @@ module Salemove
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
class
|
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.
|
32
|
-
|
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:
|
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:
|
11
|
+
date: 2018-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: airbrake
|