deimos-ruby 1.6.1 → 1.8.0.pre.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +9 -0
- data/.rubocop.yml +15 -13
- data/.ruby-version +1 -1
- data/CHANGELOG.md +30 -0
- data/Gemfile.lock +87 -80
- data/README.md +139 -15
- data/Rakefile +1 -1
- data/deimos-ruby.gemspec +3 -2
- data/docs/ARCHITECTURE.md +144 -0
- data/docs/CONFIGURATION.md +27 -0
- data/lib/deimos.rb +7 -6
- data/lib/deimos/active_record_consume/batch_consumption.rb +159 -0
- data/lib/deimos/active_record_consume/batch_slicer.rb +27 -0
- data/lib/deimos/active_record_consume/message_consumption.rb +58 -0
- data/lib/deimos/active_record_consume/schema_model_converter.rb +52 -0
- data/lib/deimos/active_record_consumer.rb +33 -75
- data/lib/deimos/active_record_producer.rb +23 -0
- data/lib/deimos/batch_consumer.rb +2 -140
- data/lib/deimos/config/configuration.rb +28 -10
- data/lib/deimos/consume/batch_consumption.rb +148 -0
- data/lib/deimos/consume/message_consumption.rb +93 -0
- data/lib/deimos/consumer.rb +79 -69
- data/lib/deimos/kafka_message.rb +1 -1
- data/lib/deimos/kafka_source.rb +29 -23
- data/lib/deimos/kafka_topic_info.rb +1 -1
- data/lib/deimos/message.rb +6 -1
- data/lib/deimos/metrics/provider.rb +0 -2
- data/lib/deimos/poll_info.rb +9 -0
- data/lib/deimos/tracing/provider.rb +0 -2
- data/lib/deimos/utils/db_poller.rb +149 -0
- data/lib/deimos/utils/db_producer.rb +8 -3
- data/lib/deimos/utils/deadlock_retry.rb +68 -0
- data/lib/deimos/utils/lag_reporter.rb +19 -26
- data/lib/deimos/version.rb +1 -1
- data/lib/generators/deimos/db_poller/templates/migration +11 -0
- data/lib/generators/deimos/db_poller/templates/rails3_migration +16 -0
- data/lib/generators/deimos/db_poller_generator.rb +48 -0
- data/lib/tasks/deimos.rake +7 -0
- data/spec/active_record_batch_consumer_spec.rb +481 -0
- data/spec/active_record_consume/batch_slicer_spec.rb +42 -0
- data/spec/active_record_consume/schema_model_converter_spec.rb +105 -0
- data/spec/active_record_consumer_spec.rb +22 -11
- data/spec/active_record_producer_spec.rb +66 -88
- data/spec/batch_consumer_spec.rb +23 -7
- data/spec/config/configuration_spec.rb +4 -0
- data/spec/consumer_spec.rb +8 -8
- data/spec/deimos_spec.rb +57 -49
- data/spec/handlers/my_batch_consumer.rb +6 -1
- data/spec/handlers/my_consumer.rb +6 -1
- data/spec/kafka_source_spec.rb +53 -0
- data/spec/message_spec.rb +19 -0
- data/spec/producer_spec.rb +3 -3
- data/spec/rake_spec.rb +1 -1
- data/spec/schemas/com/my-namespace/MySchemaCompound-key.avsc +18 -0
- data/spec/schemas/com/my-namespace/Wibble.avsc +43 -0
- data/spec/spec_helper.rb +61 -6
- data/spec/utils/db_poller_spec.rb +320 -0
- data/spec/utils/deadlock_retry_spec.rb +74 -0
- data/spec/utils/lag_reporter_spec.rb +29 -22
- metadata +61 -20
- data/lib/deimos/base_consumer.rb +0 -104
- data/lib/deimos/utils/executor.rb +0 -124
- data/lib/deimos/utils/platform_schema_validation.rb +0 -0
- data/lib/deimos/utils/signal_handler.rb +0 -68
- data/spec/utils/executor_spec.rb +0 -53
- data/spec/utils/signal_handler_spec.rb +0 -16
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deimos-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0.pre.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Orner
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: avro_turf
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sigurd
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.0.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.0.1
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: activerecord
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,19 +109,19 @@ dependencies:
|
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '1.9'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
112
|
+
name: database_cleaner
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: '1'
|
117
|
+
version: '1.7'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: '1'
|
124
|
+
version: '1.7'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: ddtrace
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -213,6 +227,9 @@ dependencies:
|
|
213
227
|
- - "~>"
|
214
228
|
- !ruby/object:Gem::Version
|
215
229
|
version: '5.2'
|
230
|
+
- - ">="
|
231
|
+
- !ruby/object:Gem::Version
|
232
|
+
version: 5.2.4.2
|
216
233
|
type: :development
|
217
234
|
prerelease: false
|
218
235
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -220,6 +237,9 @@ dependencies:
|
|
220
237
|
- - "~>"
|
221
238
|
- !ruby/object:Gem::Version
|
222
239
|
version: '5.2'
|
240
|
+
- - ">="
|
241
|
+
- !ruby/object:Gem::Version
|
242
|
+
version: 5.2.4.2
|
223
243
|
- !ruby/object:Gem::Dependency
|
224
244
|
name: rake
|
225
245
|
requirement: !ruby/object:Gem::Requirement
|
@@ -304,7 +324,7 @@ dependencies:
|
|
304
324
|
- - "~>"
|
305
325
|
- !ruby/object:Gem::Version
|
306
326
|
version: '1.3'
|
307
|
-
description:
|
327
|
+
description:
|
308
328
|
email:
|
309
329
|
- daniel.orner@wishabi.com
|
310
330
|
executables:
|
@@ -331,10 +351,15 @@ files:
|
|
331
351
|
- bin/deimos
|
332
352
|
- deimos-ruby.gemspec
|
333
353
|
- docker-compose.yml
|
354
|
+
- docs/ARCHITECTURE.md
|
334
355
|
- docs/CONFIGURATION.md
|
335
356
|
- docs/DATABASE_BACKEND.md
|
336
357
|
- docs/PULL_REQUEST_TEMPLATE.md
|
337
358
|
- lib/deimos.rb
|
359
|
+
- lib/deimos/active_record_consume/batch_consumption.rb
|
360
|
+
- lib/deimos/active_record_consume/batch_slicer.rb
|
361
|
+
- lib/deimos/active_record_consume/message_consumption.rb
|
362
|
+
- lib/deimos/active_record_consume/schema_model_converter.rb
|
338
363
|
- lib/deimos/active_record_consumer.rb
|
339
364
|
- lib/deimos/active_record_producer.rb
|
340
365
|
- lib/deimos/backends/base.rb
|
@@ -342,11 +367,12 @@ files:
|
|
342
367
|
- lib/deimos/backends/kafka.rb
|
343
368
|
- lib/deimos/backends/kafka_async.rb
|
344
369
|
- lib/deimos/backends/test.rb
|
345
|
-
- lib/deimos/base_consumer.rb
|
346
370
|
- lib/deimos/batch_consumer.rb
|
347
371
|
- lib/deimos/config/configurable.rb
|
348
372
|
- lib/deimos/config/configuration.rb
|
349
373
|
- lib/deimos/config/phobos_config.rb
|
374
|
+
- lib/deimos/consume/batch_consumption.rb
|
375
|
+
- lib/deimos/consume/message_consumption.rb
|
350
376
|
- lib/deimos/consumer.rb
|
351
377
|
- lib/deimos/instrumentation.rb
|
352
378
|
- lib/deimos/kafka_message.rb
|
@@ -359,6 +385,7 @@ files:
|
|
359
385
|
- lib/deimos/monkey_patches/phobos_cli.rb
|
360
386
|
- lib/deimos/monkey_patches/phobos_producer.rb
|
361
387
|
- lib/deimos/monkey_patches/ruby_kafka_heartbeat.rb
|
388
|
+
- lib/deimos/poll_info.rb
|
362
389
|
- lib/deimos/producer.rb
|
363
390
|
- lib/deimos/railtie.rb
|
364
391
|
- lib/deimos/schema_backends/avro_base.rb
|
@@ -373,17 +400,22 @@ files:
|
|
373
400
|
- lib/deimos/tracing/datadog.rb
|
374
401
|
- lib/deimos/tracing/mock.rb
|
375
402
|
- lib/deimos/tracing/provider.rb
|
403
|
+
- lib/deimos/utils/db_poller.rb
|
376
404
|
- lib/deimos/utils/db_producer.rb
|
377
|
-
- lib/deimos/utils/
|
405
|
+
- lib/deimos/utils/deadlock_retry.rb
|
378
406
|
- lib/deimos/utils/inline_consumer.rb
|
379
407
|
- lib/deimos/utils/lag_reporter.rb
|
380
|
-
- lib/deimos/utils/platform_schema_validation.rb
|
381
|
-
- lib/deimos/utils/signal_handler.rb
|
382
408
|
- lib/deimos/version.rb
|
383
409
|
- lib/generators/deimos/db_backend/templates/migration
|
384
410
|
- lib/generators/deimos/db_backend/templates/rails3_migration
|
385
411
|
- lib/generators/deimos/db_backend_generator.rb
|
412
|
+
- lib/generators/deimos/db_poller/templates/migration
|
413
|
+
- lib/generators/deimos/db_poller/templates/rails3_migration
|
414
|
+
- lib/generators/deimos/db_poller_generator.rb
|
386
415
|
- lib/tasks/deimos.rake
|
416
|
+
- spec/active_record_batch_consumer_spec.rb
|
417
|
+
- spec/active_record_consume/batch_slicer_spec.rb
|
418
|
+
- spec/active_record_consume/schema_model_converter_spec.rb
|
387
419
|
- spec/active_record_consumer_spec.rb
|
388
420
|
- spec/active_record_producer_spec.rb
|
389
421
|
- spec/backends/base_spec.rb
|
@@ -399,6 +431,7 @@ files:
|
|
399
431
|
- spec/handlers/my_consumer.rb
|
400
432
|
- spec/kafka_source_spec.rb
|
401
433
|
- spec/kafka_topic_info_spec.rb
|
434
|
+
- spec/message_spec.rb
|
402
435
|
- spec/phobos.bad_db.yml
|
403
436
|
- spec/phobos.yml
|
404
437
|
- spec/producer_spec.rb
|
@@ -410,18 +443,20 @@ files:
|
|
410
443
|
- spec/schema_backends/base_spec.rb
|
411
444
|
- spec/schemas/com/my-namespace/MySchema-key.avsc
|
412
445
|
- spec/schemas/com/my-namespace/MySchema.avsc
|
446
|
+
- spec/schemas/com/my-namespace/MySchemaCompound-key.avsc
|
413
447
|
- spec/schemas/com/my-namespace/MySchemaWithBooleans.avsc
|
414
448
|
- spec/schemas/com/my-namespace/MySchemaWithDateTimes.avsc
|
415
449
|
- spec/schemas/com/my-namespace/MySchemaWithId.avsc
|
416
450
|
- spec/schemas/com/my-namespace/MySchemaWithUniqueId.avsc
|
451
|
+
- spec/schemas/com/my-namespace/Wibble.avsc
|
417
452
|
- spec/schemas/com/my-namespace/Widget.avsc
|
418
453
|
- spec/schemas/com/my-namespace/WidgetTheSecond.avsc
|
419
454
|
- spec/spec_helper.rb
|
455
|
+
- spec/utils/db_poller_spec.rb
|
420
456
|
- spec/utils/db_producer_spec.rb
|
421
|
-
- spec/utils/
|
457
|
+
- spec/utils/deadlock_retry_spec.rb
|
422
458
|
- spec/utils/lag_reporter_spec.rb
|
423
459
|
- spec/utils/platform_schema_validation_spec.rb
|
424
|
-
- spec/utils/signal_handler_spec.rb
|
425
460
|
- support/deimos-solo.png
|
426
461
|
- support/deimos-with-name-next.png
|
427
462
|
- support/deimos-with-name.png
|
@@ -430,7 +465,7 @@ homepage: ''
|
|
430
465
|
licenses:
|
431
466
|
- Apache-2.0
|
432
467
|
metadata: {}
|
433
|
-
post_install_message:
|
468
|
+
post_install_message:
|
434
469
|
rdoc_options: []
|
435
470
|
require_paths:
|
436
471
|
- lib
|
@@ -441,15 +476,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
441
476
|
version: '0'
|
442
477
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
443
478
|
requirements:
|
444
|
-
- - "
|
479
|
+
- - ">"
|
445
480
|
- !ruby/object:Gem::Version
|
446
|
-
version:
|
481
|
+
version: 1.3.1
|
447
482
|
requirements: []
|
448
|
-
rubygems_version: 3.1.
|
449
|
-
signing_key:
|
483
|
+
rubygems_version: 3.1.3
|
484
|
+
signing_key:
|
450
485
|
specification_version: 4
|
451
486
|
summary: Kafka libraries for Ruby.
|
452
487
|
test_files:
|
488
|
+
- spec/active_record_batch_consumer_spec.rb
|
489
|
+
- spec/active_record_consume/batch_slicer_spec.rb
|
490
|
+
- spec/active_record_consume/schema_model_converter_spec.rb
|
453
491
|
- spec/active_record_consumer_spec.rb
|
454
492
|
- spec/active_record_producer_spec.rb
|
455
493
|
- spec/backends/base_spec.rb
|
@@ -465,6 +503,7 @@ test_files:
|
|
465
503
|
- spec/handlers/my_consumer.rb
|
466
504
|
- spec/kafka_source_spec.rb
|
467
505
|
- spec/kafka_topic_info_spec.rb
|
506
|
+
- spec/message_spec.rb
|
468
507
|
- spec/phobos.bad_db.yml
|
469
508
|
- spec/phobos.yml
|
470
509
|
- spec/producer_spec.rb
|
@@ -476,15 +515,17 @@ test_files:
|
|
476
515
|
- spec/schema_backends/base_spec.rb
|
477
516
|
- spec/schemas/com/my-namespace/MySchema-key.avsc
|
478
517
|
- spec/schemas/com/my-namespace/MySchema.avsc
|
518
|
+
- spec/schemas/com/my-namespace/MySchemaCompound-key.avsc
|
479
519
|
- spec/schemas/com/my-namespace/MySchemaWithBooleans.avsc
|
480
520
|
- spec/schemas/com/my-namespace/MySchemaWithDateTimes.avsc
|
481
521
|
- spec/schemas/com/my-namespace/MySchemaWithId.avsc
|
482
522
|
- spec/schemas/com/my-namespace/MySchemaWithUniqueId.avsc
|
523
|
+
- spec/schemas/com/my-namespace/Wibble.avsc
|
483
524
|
- spec/schemas/com/my-namespace/Widget.avsc
|
484
525
|
- spec/schemas/com/my-namespace/WidgetTheSecond.avsc
|
485
526
|
- spec/spec_helper.rb
|
527
|
+
- spec/utils/db_poller_spec.rb
|
486
528
|
- spec/utils/db_producer_spec.rb
|
487
|
-
- spec/utils/
|
529
|
+
- spec/utils/deadlock_retry_spec.rb
|
488
530
|
- spec/utils/lag_reporter_spec.rb
|
489
531
|
- spec/utils/platform_schema_validation_spec.rb
|
490
|
-
- spec/utils/signal_handler_spec.rb
|
data/lib/deimos/base_consumer.rb
DELETED
@@ -1,104 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Deimos
|
4
|
-
# Shared methods for Kafka Consumers
|
5
|
-
class BaseConsumer
|
6
|
-
include SharedConfig
|
7
|
-
|
8
|
-
class << self
|
9
|
-
# @return [Deimos::SchemaBackends::Base]
|
10
|
-
def decoder
|
11
|
-
@decoder ||= Deimos.schema_backend(schema: config[:schema],
|
12
|
-
namespace: config[:namespace])
|
13
|
-
end
|
14
|
-
|
15
|
-
# @return [Deimos::SchemaBackends::Base]
|
16
|
-
def key_decoder
|
17
|
-
@key_decoder ||= Deimos.schema_backend(schema: config[:key_schema],
|
18
|
-
namespace: config[:namespace])
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# Helper method to decode an encoded key.
|
23
|
-
# @param key [String]
|
24
|
-
# @return [Object] the decoded key.
|
25
|
-
def decode_key(key)
|
26
|
-
return nil if key.nil?
|
27
|
-
|
28
|
-
config = self.class.config
|
29
|
-
unless config[:key_configured]
|
30
|
-
raise 'No key config given - if you are not decoding keys, please use '\
|
31
|
-
'`key_config plain: true`'
|
32
|
-
end
|
33
|
-
|
34
|
-
if config[:key_field]
|
35
|
-
self.class.decoder.decode_key(key, config[:key_field])
|
36
|
-
elsif config[:key_schema]
|
37
|
-
self.class.key_decoder.decode(key, schema: config[:key_schema])
|
38
|
-
else # no encoding
|
39
|
-
key
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
protected
|
44
|
-
|
45
|
-
# @param payload [Hash|String]
|
46
|
-
# @param metadata [Hash]
|
47
|
-
def _with_error_span(payload, metadata)
|
48
|
-
@span = Deimos.config.tracer&.start(
|
49
|
-
'deimos-consumer',
|
50
|
-
resource: self.class.name.gsub('::', '-')
|
51
|
-
)
|
52
|
-
yield
|
53
|
-
rescue StandardError => e
|
54
|
-
_handle_error(e, payload, metadata)
|
55
|
-
ensure
|
56
|
-
Deimos.config.tracer&.finish(@span)
|
57
|
-
end
|
58
|
-
|
59
|
-
def _report_time_delayed(payload, metadata)
|
60
|
-
return if payload.nil? || payload['timestamp'].blank?
|
61
|
-
|
62
|
-
begin
|
63
|
-
time_delayed = Time.now.in_time_zone - payload['timestamp'].to_datetime
|
64
|
-
rescue ArgumentError
|
65
|
-
Deimos.config.logger.info(
|
66
|
-
message: "Error parsing timestamp! #{payload['timestamp']}"
|
67
|
-
)
|
68
|
-
return
|
69
|
-
end
|
70
|
-
Deimos.config.metrics&.histogram('handler', time_delayed, tags: %W(
|
71
|
-
time:time_delayed
|
72
|
-
topic:#{metadata[:topic]}
|
73
|
-
))
|
74
|
-
end
|
75
|
-
|
76
|
-
# Overrideable method to determine if a given error should be considered
|
77
|
-
# "fatal" and always be reraised.
|
78
|
-
# @param error [Exception]
|
79
|
-
# @param payload [Hash]
|
80
|
-
# @param metadata [Hash]
|
81
|
-
# @return [Boolean]
|
82
|
-
def fatal_error?(_error, _payload, _metadata)
|
83
|
-
false
|
84
|
-
end
|
85
|
-
|
86
|
-
# @param exception [Exception]
|
87
|
-
# @param payload [Hash]
|
88
|
-
# @param metadata [Hash]
|
89
|
-
def _handle_error(exception, payload, metadata)
|
90
|
-
Deimos.config.tracer&.set_error(@span, exception)
|
91
|
-
|
92
|
-
raise if Deimos.config.consumers.reraise_errors ||
|
93
|
-
Deimos.config.consumers.fatal_error&.call(exception, payload, metadata) ||
|
94
|
-
fatal_error?(exception, payload, metadata)
|
95
|
-
end
|
96
|
-
|
97
|
-
# @param _time_taken [Float]
|
98
|
-
# @param _payload [Hash]
|
99
|
-
# @param _metadata [Hash]
|
100
|
-
def _handle_success(_time_taken, _payload, _metadata)
|
101
|
-
raise NotImplementedError
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
@@ -1,124 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# rubocop:disable Lint/RescueException
|
4
|
-
module Deimos
|
5
|
-
module Utils
|
6
|
-
# Mostly copied from Phobos::Executor. We should DRY this up by putting in a
|
7
|
-
# PR to make it more generic. Might even make sense to move to a separate
|
8
|
-
# gem.
|
9
|
-
class Executor
|
10
|
-
# @return [Array<#start, #stop, #id>]
|
11
|
-
attr_accessor :runners
|
12
|
-
|
13
|
-
# @param runners [Array<#start, #stop, #id>] A list of objects that can be
|
14
|
-
# started or stopped.
|
15
|
-
# @param logger [Logger]
|
16
|
-
# @param sleep_seconds [Integer] Use a fixed time to sleep between
|
17
|
-
# failed runs instead of using an exponential backoff.
|
18
|
-
def initialize(runners, sleep_seconds: nil, logger: Logger.new(STDOUT))
|
19
|
-
@threads = Concurrent::Array.new
|
20
|
-
@runners = runners
|
21
|
-
@logger = logger
|
22
|
-
@sleep_seconds = sleep_seconds
|
23
|
-
end
|
24
|
-
|
25
|
-
# Start the executor.
|
26
|
-
def start
|
27
|
-
@logger.info('Starting executor')
|
28
|
-
@signal_to_stop = false
|
29
|
-
@threads.clear
|
30
|
-
@thread_pool = Concurrent::FixedThreadPool.new(@runners.size)
|
31
|
-
|
32
|
-
@runners.each do |runner|
|
33
|
-
@thread_pool.post do
|
34
|
-
thread = Thread.current
|
35
|
-
thread.abort_on_exception = true
|
36
|
-
@threads << thread
|
37
|
-
run_object(runner)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
true
|
42
|
-
end
|
43
|
-
|
44
|
-
# Stop the executor.
|
45
|
-
def stop
|
46
|
-
return if @signal_to_stop
|
47
|
-
|
48
|
-
@logger.info('Stopping executor')
|
49
|
-
@signal_to_stop = true
|
50
|
-
@runners.each(&:stop)
|
51
|
-
@threads.select(&:alive?).each do |thread|
|
52
|
-
begin
|
53
|
-
thread.wakeup
|
54
|
-
rescue StandardError
|
55
|
-
nil
|
56
|
-
end
|
57
|
-
end
|
58
|
-
@thread_pool&.shutdown
|
59
|
-
@thread_pool&.wait_for_termination
|
60
|
-
@logger.info('Executor stopped')
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
# @param exception [Throwable]
|
66
|
-
# @return [Hash]
|
67
|
-
def error_metadata(exception)
|
68
|
-
{
|
69
|
-
exception_class: exception.class.name,
|
70
|
-
exception_message: exception.message,
|
71
|
-
backtrace: exception.backtrace
|
72
|
-
}
|
73
|
-
end
|
74
|
-
|
75
|
-
def run_object(runner)
|
76
|
-
retry_count = 0
|
77
|
-
|
78
|
-
begin
|
79
|
-
@logger.info("Running #{runner.id}")
|
80
|
-
runner.start
|
81
|
-
retry_count = 0 # success - reset retry count
|
82
|
-
rescue Exception => e
|
83
|
-
handle_crashed_runner(runner, e, retry_count)
|
84
|
-
retry_count += 1
|
85
|
-
retry unless @signal_to_stop
|
86
|
-
end
|
87
|
-
rescue Exception => e
|
88
|
-
@logger.error("Failed to run listener (#{e.message}) #{error_metadata(e)}")
|
89
|
-
raise e
|
90
|
-
end
|
91
|
-
|
92
|
-
# @return [ExponentialBackoff]
|
93
|
-
def create_exponential_backoff
|
94
|
-
min = 1
|
95
|
-
max = 60
|
96
|
-
ExponentialBackoff.new(min, max).tap do |backoff|
|
97
|
-
backoff.randomize_factor = rand
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# When "runner#start" is interrupted / crashes we assume it's
|
102
|
-
# safe to be called again
|
103
|
-
def handle_crashed_runner(runner, error, retry_count)
|
104
|
-
interval = if @sleep_seconds
|
105
|
-
@sleep_seconds
|
106
|
-
else
|
107
|
-
backoff = create_exponential_backoff
|
108
|
-
backoff.interval_at(retry_count).round(2)
|
109
|
-
end
|
110
|
-
|
111
|
-
metadata = {
|
112
|
-
listener_id: runner.id,
|
113
|
-
retry_count: retry_count,
|
114
|
-
waiting_time: interval
|
115
|
-
}.merge(error_metadata(error))
|
116
|
-
|
117
|
-
@logger.error("Runner crashed, waiting #{interval}s (#{error.message}) #{metadata}")
|
118
|
-
sleep(interval)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
# rubocop:enable Lint/RescueException
|