atatus 1.0.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/Gemfile +72 -22
  4. data/LICENSE +1 -1
  5. data/atatus.gemspec +2 -2
  6. data/lib/atatus.rb +76 -16
  7. data/lib/atatus/agent.rb +78 -29
  8. data/lib/atatus/central_config.rb +72 -27
  9. data/lib/atatus/central_config/cache_control.rb +18 -1
  10. data/lib/atatus/child_durations.rb +64 -0
  11. data/lib/atatus/collector/base.rb +115 -35
  12. data/lib/atatus/collector/builder.rb +104 -33
  13. data/lib/atatus/collector/hist.rb +54 -0
  14. data/lib/atatus/collector/layer.rb +3 -0
  15. data/lib/atatus/collector/transport.rb +44 -10
  16. data/lib/atatus/config.rb +130 -29
  17. data/lib/atatus/config/bytes.rb +17 -0
  18. data/lib/atatus/config/duration.rb +17 -0
  19. data/lib/atatus/config/options.rb +29 -9
  20. data/lib/atatus/config/regexp_list.rb +17 -0
  21. data/lib/atatus/config/wildcard_pattern_list.rb +64 -0
  22. data/lib/atatus/context.rb +32 -1
  23. data/lib/atatus/context/request.rb +17 -0
  24. data/lib/atatus/context/request/socket.rb +18 -1
  25. data/lib/atatus/context/request/url.rb +17 -0
  26. data/lib/atatus/context/response.rb +27 -2
  27. data/lib/atatus/context/user.rb +17 -0
  28. data/lib/atatus/context_builder.rb +19 -4
  29. data/lib/atatus/deprecations.rb +17 -0
  30. data/lib/atatus/error.rb +27 -0
  31. data/lib/atatus/error/exception.rb +24 -0
  32. data/lib/atatus/error/log.rb +17 -0
  33. data/lib/atatus/error_builder.rb +17 -2
  34. data/lib/atatus/grape.rb +62 -0
  35. data/lib/atatus/graphql.rb +91 -0
  36. data/lib/atatus/grpc.rb +99 -0
  37. data/lib/atatus/instrumenter.rb +135 -30
  38. data/lib/atatus/internal_error.rb +17 -0
  39. data/lib/atatus/logging.rb +17 -2
  40. data/lib/atatus/metadata.rb +17 -0
  41. data/lib/atatus/metadata/process_info.rb +17 -0
  42. data/lib/atatus/metadata/service_info.rb +21 -6
  43. data/lib/atatus/metadata/system_info.rb +22 -3
  44. data/lib/atatus/metadata/system_info/container_info.rb +49 -10
  45. data/lib/atatus/metadata/system_info/hw_info.rb +1 -1
  46. data/lib/atatus/metrics.rb +69 -27
  47. data/lib/atatus/metrics/breakdown_set.rb +31 -0
  48. data/lib/atatus/metrics/{cpu_mem.rb → cpu_mem_set.rb} +110 -63
  49. data/lib/atatus/metrics/metric.rb +140 -0
  50. data/lib/atatus/metrics/set.rb +123 -0
  51. data/lib/atatus/metrics/span_scoped_set.rb +56 -0
  52. data/lib/atatus/metrics/transaction_set.rb +26 -0
  53. data/lib/atatus/metrics/vm_set.rb +58 -0
  54. data/lib/atatus/metricset.rb +48 -4
  55. data/lib/atatus/middleware.rb +28 -8
  56. data/lib/atatus/naively_hashable.rb +17 -0
  57. data/lib/atatus/normalizers.rb +23 -9
  58. data/lib/atatus/normalizers/grape.rb +22 -0
  59. data/lib/atatus/normalizers/grape/endpoint_run.rb +65 -0
  60. data/lib/atatus/normalizers/rails.rb +27 -0
  61. data/lib/atatus/normalizers/rails/action_controller.rb +44 -0
  62. data/lib/atatus/normalizers/rails/action_mailer.rb +43 -0
  63. data/lib/atatus/normalizers/{action_view.rb → rails/action_view.rb} +17 -0
  64. data/lib/atatus/normalizers/rails/active_record.rb +80 -0
  65. data/lib/atatus/opentracing.rb +75 -42
  66. data/lib/atatus/rails.rb +29 -13
  67. data/lib/atatus/railtie.rb +19 -6
  68. data/lib/atatus/resque.rb +29 -0
  69. data/lib/atatus/sinatra.rb +53 -0
  70. data/lib/atatus/span.rb +48 -18
  71. data/lib/atatus/span/context.rb +43 -28
  72. data/lib/atatus/span/context/db.rb +43 -0
  73. data/lib/atatus/span/context/destination.rb +77 -0
  74. data/lib/atatus/span/context/http.rb +43 -0
  75. data/lib/atatus/span_helpers.rb +32 -6
  76. data/lib/atatus/spies.rb +33 -15
  77. data/lib/atatus/spies/action_dispatch.rb +27 -6
  78. data/lib/atatus/spies/delayed_job.rb +26 -5
  79. data/lib/atatus/spies/dynamo_db.rb +62 -0
  80. data/lib/atatus/spies/elasticsearch.rb +53 -7
  81. data/lib/atatus/spies/faraday.rb +54 -20
  82. data/lib/atatus/spies/http.rb +36 -6
  83. data/lib/atatus/spies/json.rb +18 -0
  84. data/lib/atatus/spies/mongo.rb +41 -10
  85. data/lib/atatus/spies/net_http.rb +52 -11
  86. data/lib/atatus/spies/rake.rb +42 -23
  87. data/lib/atatus/spies/redis.rb +17 -0
  88. data/lib/atatus/spies/resque.rb +57 -0
  89. data/lib/atatus/spies/sequel.rb +54 -17
  90. data/lib/atatus/spies/shoryuken.rb +69 -0
  91. data/lib/atatus/spies/sidekiq.rb +46 -25
  92. data/lib/atatus/spies/sinatra.rb +20 -4
  93. data/lib/atatus/spies/sneakers.rb +74 -0
  94. data/lib/atatus/spies/sucker_punch.rb +58 -0
  95. data/lib/atatus/spies/tilt.rb +20 -1
  96. data/lib/atatus/sql.rb +36 -0
  97. data/lib/atatus/sql/signature.rb +169 -0
  98. data/lib/atatus/sql/tokenizer.rb +264 -0
  99. data/lib/atatus/sql/tokens.rb +63 -0
  100. data/lib/atatus/sql_summarizer.rb +24 -6
  101. data/lib/atatus/stacktrace.rb +17 -0
  102. data/lib/atatus/stacktrace/frame.rb +17 -3
  103. data/lib/atatus/stacktrace_builder.rb +34 -10
  104. data/lib/atatus/subscriber.rb +23 -4
  105. data/lib/atatus/trace_context.rb +84 -51
  106. data/lib/atatus/trace_context/traceparent.rb +111 -0
  107. data/lib/atatus/trace_context/tracestate.rb +148 -0
  108. data/lib/atatus/transaction.rb +75 -19
  109. data/lib/atatus/transport/base.rb +44 -27
  110. data/lib/atatus/transport/connection.rb +28 -72
  111. data/lib/atatus/transport/connection/http.rb +58 -35
  112. data/lib/atatus/transport/connection/proxy_pipe.rb +24 -5
  113. data/lib/atatus/transport/filters.rb +18 -1
  114. data/lib/atatus/transport/filters/hash_sanitizer.rb +77 -0
  115. data/lib/atatus/transport/filters/secrets_filter.rb +30 -55
  116. data/lib/atatus/transport/headers.rb +83 -0
  117. data/lib/atatus/transport/serializers.rb +17 -5
  118. data/lib/atatus/transport/serializers/context_serializer.rb +30 -3
  119. data/lib/atatus/transport/serializers/error_serializer.rb +17 -2
  120. data/lib/atatus/transport/serializers/metadata_serializer.rb +44 -22
  121. data/lib/atatus/transport/serializers/metricset_serializer.rb +34 -6
  122. data/lib/atatus/transport/serializers/span_serializer.rb +47 -12
  123. data/lib/atatus/transport/serializers/transaction_serializer.rb +18 -2
  124. data/lib/atatus/transport/user_agent.rb +48 -0
  125. data/lib/atatus/transport/worker.rb +31 -7
  126. data/lib/atatus/util.rb +22 -1
  127. data/lib/atatus/util/inflector.rb +17 -0
  128. data/lib/atatus/util/lru_cache.rb +17 -0
  129. data/lib/atatus/util/throttle.rb +17 -0
  130. data/lib/atatus/version.rb +19 -1
  131. metadata +46 -26
  132. data/Rakefile +0 -19
  133. data/bench/.gitignore +0 -2
  134. data/bench/app.rb +0 -53
  135. data/bench/benchmark.rb +0 -36
  136. data/bench/report.rb +0 -55
  137. data/bench/rubyprof.rb +0 -39
  138. data/bench/stackprof.rb +0 -23
  139. data/bin/build_docs +0 -5
  140. data/bin/console +0 -15
  141. data/bin/setup +0 -8
  142. data/bin/with_framework +0 -7
  143. data/lib/atatus/metrics/vm.rb +0 -60
  144. data/lib/atatus/normalizers/action_controller.rb +0 -27
  145. data/lib/atatus/normalizers/action_mailer.rb +0 -26
  146. data/lib/atatus/normalizers/active_record.rb +0 -45
  147. data/lib/atatus/util/prefixed_logger.rb +0 -18
  148. data/vendor/.gitkeep +0 -0
@@ -0,0 +1,111 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Atatus
21
+ class TraceContext
22
+ # @api private
23
+ class Traceparent
24
+ VERSION = '00'
25
+ HEX_REGEX = /[^[:xdigit:]]/.freeze
26
+
27
+ TRACE_ID_LENGTH = 16
28
+ ID_LENGTH = 8
29
+
30
+ # rubocop:disable Metrics/ParameterLists
31
+ def initialize(
32
+ version: VERSION,
33
+ trace_id: nil,
34
+ span_id: nil,
35
+ id: nil,
36
+ recorded: true
37
+ )
38
+ @version = version
39
+ @trace_id = trace_id || hex(TRACE_ID_LENGTH)
40
+ # TODO: rename span_id kw arg to parent_id with next major version bump
41
+ @parent_id = span_id
42
+ @id = id || hex(ID_LENGTH)
43
+ @recorded = recorded
44
+ end
45
+ # rubocop:enable Metrics/ParameterLists
46
+
47
+ attr_accessor :version, :id, :trace_id, :parent_id, :recorded
48
+
49
+ alias :recorded? :recorded
50
+
51
+ def self.parse(header)
52
+ raise_invalid(header) unless header.length == 55
53
+ raise_invalid(header) unless header[0..1] == VERSION
54
+
55
+ new.tap do |t|
56
+ t.version, t.trace_id, t.parent_id, t.flags =
57
+ header.split('-').tap do |values|
58
+ values[-1] = Util.hex_to_bits(values[-1])
59
+ end
60
+
61
+ raise_invalid(header) if HEX_REGEX =~ t.trace_id
62
+ raise_invalid(header) if HEX_REGEX =~ t.parent_id
63
+ end
64
+ end
65
+
66
+ class << self
67
+ private
68
+
69
+ def raise_invalid(header)
70
+ raise InvalidTraceparentHeader,
71
+ "Couldn't parse invalid traceparent header: #{header.inspect}"
72
+ end
73
+ end
74
+
75
+ def flags=(flags)
76
+ @flags = flags
77
+
78
+ self.recorded = flags[7] == '1'
79
+ end
80
+
81
+ def flags
82
+ format('0000000%d', recorded? ? 1 : 0)
83
+ end
84
+
85
+ def hex_flags
86
+ format('%02x', flags.to_i(2))
87
+ end
88
+
89
+ def ensure_parent_id
90
+ @parent_id ||= hex(ID_LENGTH)
91
+ end
92
+
93
+ def child
94
+ dup.tap do |copy|
95
+ copy.parent_id = id
96
+ copy.id = hex(ID_LENGTH)
97
+ end
98
+ end
99
+
100
+ def to_header
101
+ format('%s-%s-%s-%s', version, trace_id, id, hex_flags)
102
+ end
103
+
104
+ private
105
+
106
+ def hex(len)
107
+ SecureRandom.hex(len)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,148 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Atatus
21
+ class TraceContext
22
+ # @api private
23
+ class Tracestate
24
+ # @api private
25
+ class Entry
26
+ def initialize(key, value)
27
+ @key = key
28
+ @value = value
29
+ end
30
+
31
+ attr_reader :key, :value
32
+
33
+ def to_s
34
+ "#{key}=#{value}"
35
+ end
36
+ end
37
+
38
+ class EsEntry
39
+ ASSIGN = ':'
40
+ SPLIT = ';'
41
+
42
+ SHORT_TO_LONG = { 's' => 'sample_rate' }
43
+ LONG_TO_SHORT = { 'sample_rate' => 's' }
44
+
45
+ def initialize(values = nil)
46
+ parse(values)
47
+ end
48
+
49
+ attr_reader :sample_rate
50
+
51
+ def key
52
+ 'es'
53
+ end
54
+
55
+ def value
56
+ LONG_TO_SHORT.map do |l, s|
57
+ "#{s}#{ASSIGN}#{send(l)}"
58
+ end.join(SPLIT)
59
+ end
60
+
61
+ def empty?
62
+ !sample_rate
63
+ end
64
+
65
+ def sample_rate=(val)
66
+ float = Float(val).round(3)
67
+
68
+ return nil unless (0.0..1.0).include?(float)
69
+
70
+ @sample_rate = float
71
+ rescue ArgumentError => e
72
+ nil
73
+ end
74
+
75
+ def to_s
76
+ return nil if empty?
77
+
78
+ "es=#{value}"
79
+ end
80
+
81
+ private
82
+
83
+ def parse(values)
84
+ return unless values
85
+
86
+ values.split(SPLIT).map do |kv|
87
+ k, v = kv.split(ASSIGN)
88
+ next unless SHORT_TO_LONG.keys.include?(k)
89
+ send("#{SHORT_TO_LONG[k]}=", v)
90
+ end
91
+ end
92
+ end
93
+
94
+ extend Forwardable
95
+
96
+ def initialize(entries: {}, sample_rate: nil)
97
+ @entries = entries
98
+
99
+ self.sample_rate = sample_rate if sample_rate
100
+ end
101
+
102
+ attr_accessor :entries
103
+
104
+ def_delegators :es_entry, :sample_rate, :sample_rate=
105
+
106
+ def self.parse(header)
107
+ entries =
108
+ split_by_nl_and_comma(header)
109
+ .each_with_object({}) do |entry, hsh|
110
+ k, v = entry.split('=')
111
+
112
+ hsh[k] =
113
+ case k
114
+ when 'es' then EsEntry.new(v)
115
+ else Entry.new(k, v)
116
+ end
117
+ end
118
+
119
+ new(entries: entries)
120
+ end
121
+
122
+ def to_header
123
+ return "" unless entries.any?
124
+
125
+ entries.values.map(&:to_s).join(',')
126
+ end
127
+
128
+ private
129
+
130
+ def es_entry
131
+ # lazy generate this so we only add it if necessary
132
+ entries['es'] ||= EsEntry.new
133
+ end
134
+
135
+ class << self
136
+ private
137
+
138
+ def split_by_nl_and_comma(str)
139
+ # HTTP allows multiple headers with the same name, eg. multiple
140
+ # Set-Cookie headers per response.
141
+ # Rack handles this by joining the headers under the same key, separated
142
+ # by newlines, see https://www.rubydoc.info/github/rack/rack/file/SPEC
143
+ String(str).split("\n").map { |s| s.split(',') }.flatten
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -1,36 +1,71 @@
1
- # frozen_string_literal: true
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
2
17
 
3
- require 'securerandom'
4
- require 'forwardable'
18
+ # frozen_string_literal: true
5
19
 
6
20
  module Atatus
7
21
  # @api private
8
22
  class Transaction
9
23
  extend Forwardable
24
+ include ChildDurations::Methods
10
25
 
11
26
  def_delegators :@trace_context,
12
27
  :trace_id, :parent_id, :id, :ensure_parent_id
13
28
 
14
29
  DEFAULT_TYPE = 'custom'
30
+ MUTEX = Mutex.new
15
31
 
16
32
  # rubocop:disable Metrics/ParameterLists
17
33
  def initialize(
18
34
  name = nil,
19
35
  type = nil,
20
36
  sampled: true,
37
+ sample_rate: 1,
21
38
  context: nil,
22
- labels: nil,
39
+ config:,
23
40
  trace_context: nil
24
41
  )
25
42
  @name = name
26
43
  @type = type || DEFAULT_TYPE
44
+ @config = config
45
+
46
+ # Cache these values in case they are changed during the
47
+ # transaction's lifetime via the remote config
48
+ @span_frames_min_duration = config.span_frames_min_duration
49
+ @collect_metrics = config.collect_metrics?
50
+ @breakdown_metrics = config.breakdown_metrics?
51
+ @framework_name = config.framework_name
52
+ @transaction_max_spans = config.transaction_max_spans
53
+ @default_labels = config.default_labels
27
54
 
28
55
  @sampled = sampled
56
+ @sample_rate = sample_rate
29
57
 
30
58
  @context = context || Context.new # TODO: Lazy generate this?
31
- Util.reverse_merge!(@context.labels, labels) if labels
59
+ if @default_labels
60
+ Util.reverse_merge!(@context.labels, @default_labels)
61
+ end
32
62
 
33
- @trace_context = trace_context || TraceContext.new(recorded: sampled)
63
+ unless (@trace_context = trace_context)
64
+ @trace_context = TraceContext.new(
65
+ traceparent: TraceContext::Traceparent.new(recorded: sampled),
66
+ tracestate: TraceContext::Tracestate.new(sample_rate: sampled ? sample_rate : 0)
67
+ )
68
+ end
34
69
 
35
70
  @started_spans = 0
36
71
  @dropped_spans = 0
@@ -39,10 +74,26 @@ module Atatus
39
74
  end
40
75
  # rubocop:enable Metrics/ParameterLists
41
76
 
42
- attr_accessor :name, :type, :result, :spans
77
+ attr_accessor :name, :type, :result, :spans, :ruby_time
78
+
79
+ attr_reader(
80
+ :breakdown_metrics,
81
+ :collect_metrics,
82
+ :context,
83
+ :dropped_spans,
84
+ :duration,
85
+ :framework_name,
86
+ :notifications,
87
+ :self_time,
88
+ :sample_rate,
89
+ :span_frames_min_duration,
90
+ :started_spans,
91
+ :timestamp,
92
+ :trace_context,
93
+ :transaction_max_spans
94
+ )
43
95
 
44
- attr_reader :context, :duration, :started_spans, :dropped_spans,
45
- :timestamp, :trace_context, :notifications
96
+ alias :collect_metrics? :collect_metrics
46
97
 
47
98
  def sampled?
48
99
  @sampled
@@ -63,6 +114,8 @@ module Atatus
63
114
  def stop(clock_end = Util.monotonic_micros)
64
115
  raise 'Transaction not yet start' unless timestamp
65
116
  @duration = clock_end - @clock_start
117
+ @self_time = @duration - child_durations.duration
118
+
66
119
  self
67
120
  end
68
121
 
@@ -75,21 +128,24 @@ module Atatus
75
128
  # spans
76
129
 
77
130
  def inc_started_spans!
78
- @started_spans += 1
131
+ MUTEX.synchronize do
132
+ @started_spans += 1
133
+ if @started_spans > transaction_max_spans
134
+ @dropped_spans += 1
135
+ return false
136
+ end
137
+ end
138
+ true
79
139
  end
80
140
 
81
- def inc_dropped_spans!
82
- @dropped_spans += 1
83
- end
141
+ # context
84
142
 
85
- def max_spans_reached?(config)
86
- started_spans > config.transaction_max_spans
143
+ def add_response(status = nil, **args)
144
+ context.response = Context::Response.new(status, **args)
87
145
  end
88
146
 
89
- # context
90
-
91
- def add_response(*args)
92
- context.response = Context::Response.new(*args)
147
+ def set_user(user)
148
+ context.user = Context::User.infer(@config, user)
93
149
  end
94
150
 
95
151
  def inspect
@@ -1,15 +1,35 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
1
18
  # frozen_string_literal: true
2
19
 
3
20
  require 'atatus/metadata'
21
+ require 'atatus/transport/user_agent'
22
+ require 'atatus/transport/headers'
4
23
  require 'atatus/transport/connection'
5
24
  require 'atatus/transport/worker'
6
25
  require 'atatus/transport/serializers'
7
26
  require 'atatus/transport/filters'
27
+ require 'atatus/transport/connection/http'
28
+
8
29
  require 'atatus/util/throttle'
9
30
 
10
31
  module Atatus
11
32
  module Transport
12
- # rubocop:disable Metrics/ClassLength
13
33
  # @api private
14
34
  class Base
15
35
  include Logging
@@ -28,7 +48,6 @@ module Atatus
28
48
  @stopped = Concurrent::AtomicBoolean.new
29
49
  @workers = Array.new(config.pool_size)
30
50
 
31
- @watcher_mutex = Mutex.new
32
51
  @worker_mutex = Mutex.new
33
52
  end
34
53
 
@@ -36,9 +55,13 @@ module Atatus
36
55
 
37
56
  def start
38
57
  debug '%s: Starting Transport', pid_str
58
+ # Set @stopped to false first, in case transport is restarted;
59
+ # ensure_worker_count requires @stopped to be false
60
+ # ~estolfo
61
+ @stopped.make_false unless @stopped.false?
39
62
 
40
- ensure_watcher_running
41
63
  ensure_worker_count
64
+ create_watcher
42
65
  end
43
66
 
44
67
  def stop
@@ -50,14 +73,13 @@ module Atatus
50
73
  stop_workers
51
74
  end
52
75
 
53
- # rubocop:disable Metrics/MethodLength
54
76
  def submit(resource)
55
77
  if @stopped.true?
56
78
  warn '%s: Transport stopping, no new events accepted', pid_str
79
+ debug 'Dropping: %s', resource.inspect
57
80
  return false
58
81
  end
59
82
 
60
- ensure_watcher_running
61
83
  queue.push(resource, true)
62
84
 
63
85
  true
@@ -68,31 +90,31 @@ module Atatus
68
90
  error '%s: Failed adding to the transport queue: %p', pid_str, e.inspect
69
91
  nil
70
92
  end
71
- # rubocop:enable Metrics/MethodLength
72
93
 
73
94
  def add_filter(key, callback)
74
95
  @filters.add(key, callback)
75
96
  end
76
97
 
98
+ def handle_forking!
99
+ # We can't just stop and start again because the StopMessage
100
+ # will then be the first message processed when the transport is
101
+ # restarted.
102
+ stop_watcher
103
+ ensure_worker_count
104
+ create_watcher
105
+ end
106
+
77
107
  private
78
108
 
79
109
  def pid_str
80
110
  format('[PID:%s]', Process.pid)
81
111
  end
82
112
 
83
- def ensure_watcher_running
84
- # pid has changed == we've forked
85
- return if @pid == Process.pid
86
-
87
- @watcher_mutex.synchronize do
88
- return if @pid == Process.pid
89
- @pid = Process.pid
90
-
91
- @watcher = Concurrent::TimerTask.execute(
92
- execution_interval: WATCHER_EXECUTION_INTERVAL,
93
- timeout_interval: WATCHER_TIMEOUT_INTERVAL
94
- ) { ensure_worker_count }
95
- end
113
+ def create_watcher
114
+ @watcher = Concurrent::TimerTask.execute(
115
+ execution_interval: WATCHER_EXECUTION_INTERVAL,
116
+ timeout_interval: WATCHER_TIMEOUT_INTERVAL
117
+ ) { ensure_worker_count }
96
118
  end
97
119
 
98
120
  def ensure_worker_count
@@ -124,7 +146,6 @@ module Atatus
124
146
  end
125
147
  end
126
148
 
127
- # rubocop:disable Metrics/MethodLength
128
149
  def stop_workers
129
150
  debug '%s: Stopping workers', pid_str
130
151
 
@@ -142,10 +163,10 @@ module Atatus
142
163
  thread.kill
143
164
  end
144
165
 
145
- @workers.clear
166
+ # Maintain the @worker array size for when transport is restarted
167
+ @workers.fill(nil)
146
168
  end
147
169
  end
148
- # rubocop:enable Metrics/MethodLength
149
170
 
150
171
  def send_stop_messages
151
172
  config.pool_size.times { queue.push(Worker::StopMessage.new, true) }
@@ -154,10 +175,7 @@ module Atatus
154
175
  end
155
176
 
156
177
  def stop_watcher
157
- @watcher_mutex.synchronize do
158
- return if watcher.nil? || @pid != Process.pid
159
- watcher.shutdown
160
- end
178
+ watcher&.shutdown
161
179
  end
162
180
 
163
181
  def throttled_queue_full_warning
@@ -169,6 +187,5 @@ module Atatus
169
187
  end).call
170
188
  end
171
189
  end
172
- # rubocop:enable Metrics/ClassLength
173
190
  end
174
191
  end