activesupport 7.0.0.alpha2 → 7.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +80 -0
  3. data/lib/active_support/cache/mem_cache_store.rb +9 -5
  4. data/lib/active_support/cache/memory_store.rb +2 -2
  5. data/lib/active_support/cache/redis_cache_store.rb +3 -8
  6. data/lib/active_support/cache/strategy/local_cache.rb +6 -12
  7. data/lib/active_support/callbacks.rb +145 -50
  8. data/lib/active_support/code_generator.rb +65 -0
  9. data/lib/active_support/core_ext/array/conversions.rb +3 -1
  10. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  11. data/lib/active_support/core_ext/array.rb +1 -0
  12. data/lib/active_support/core_ext/class/subclasses.rb +4 -2
  13. data/lib/active_support/core_ext/date/calculations.rb +2 -2
  14. data/lib/active_support/core_ext/date/conversions.rb +3 -3
  15. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  16. data/lib/active_support/core_ext/date.rb +1 -0
  17. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  18. data/lib/active_support/core_ext/date_time/conversions.rb +5 -5
  19. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  20. data/lib/active_support/core_ext/date_time.rb +1 -0
  21. data/lib/active_support/core_ext/digest/uuid.rb +26 -1
  22. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  23. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  24. data/lib/active_support/core_ext/numeric/conversions.rb +78 -75
  25. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  26. data/lib/active_support/core_ext/numeric.rb +1 -0
  27. data/lib/active_support/core_ext/object/with_options.rb +20 -1
  28. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  29. data/lib/active_support/core_ext/pathname.rb +3 -0
  30. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  31. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  32. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
  33. data/lib/active_support/core_ext/range.rb +1 -1
  34. data/lib/active_support/core_ext/time/calculations.rb +1 -1
  35. data/lib/active_support/core_ext/time/conversions.rb +4 -3
  36. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  37. data/lib/active_support/core_ext/time/zones.rb +2 -2
  38. data/lib/active_support/core_ext/time.rb +1 -0
  39. data/lib/active_support/core_ext/uri.rb +3 -13
  40. data/lib/active_support/core_ext.rb +1 -0
  41. data/lib/active_support/current_attributes.rb +26 -25
  42. data/lib/active_support/descendants_tracker.rb +175 -69
  43. data/lib/active_support/error_reporter.rb +117 -0
  44. data/lib/active_support/execution_context/test_helper.rb +13 -0
  45. data/lib/active_support/execution_context.rb +53 -0
  46. data/lib/active_support/execution_wrapper.rb +30 -4
  47. data/lib/active_support/executor/test_helper.rb +7 -0
  48. data/lib/active_support/fork_tracker.rb +18 -9
  49. data/lib/active_support/gem_version.rb +1 -1
  50. data/lib/active_support/html_safe_translation.rb +43 -0
  51. data/lib/active_support/i18n_railtie.rb +1 -1
  52. data/lib/active_support/inflector/inflections.rb +12 -3
  53. data/lib/active_support/inflector/methods.rb +2 -2
  54. data/lib/active_support/isolated_execution_state.rb +56 -0
  55. data/lib/active_support/logger_thread_safe_level.rb +2 -3
  56. data/lib/active_support/message_encryptor.rb +5 -0
  57. data/lib/active_support/multibyte/unicode.rb +0 -12
  58. data/lib/active_support/notifications/fanout.rb +61 -55
  59. data/lib/active_support/notifications/instrumenter.rb +15 -15
  60. data/lib/active_support/notifications.rb +5 -21
  61. data/lib/active_support/option_merger.rb +4 -0
  62. data/lib/active_support/per_thread_registry.rb +4 -0
  63. data/lib/active_support/railtie.rb +38 -11
  64. data/lib/active_support/ruby_features.rb +7 -0
  65. data/lib/active_support/subscriber.rb +2 -18
  66. data/lib/active_support/tagged_logging.rb +1 -1
  67. data/lib/active_support/testing/deprecation.rb +52 -1
  68. data/lib/active_support/testing/isolation.rb +1 -1
  69. data/lib/active_support/time_with_zone.rb +34 -6
  70. data/lib/active_support/values/time_zone.rb +5 -0
  71. data/lib/active_support/xml_mini.rb +3 -3
  72. data/lib/active_support.rb +7 -4
  73. metadata +23 -6
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module ExecutionContext # :nodoc:
5
+ @after_change_callbacks = []
6
+ class << self
7
+ def after_change(&block)
8
+ @after_change_callbacks << block
9
+ end
10
+
11
+ # Updates the execution context. If a block is given, it resets the provided keys to their
12
+ # previous value once the block exits.
13
+ def set(**options)
14
+ options.symbolize_keys!
15
+ keys = options.keys
16
+
17
+ store = self.store
18
+
19
+ previous_context = keys.zip(store.values_at(*keys)).to_h
20
+
21
+ store.merge!(options)
22
+ @after_change_callbacks.each(&:call)
23
+
24
+ if block_given?
25
+ begin
26
+ yield
27
+ ensure
28
+ store.merge!(previous_context)
29
+ @after_change_callbacks.each(&:call)
30
+ end
31
+ end
32
+ end
33
+
34
+ def []=(key, value)
35
+ store[key.to_sym] = value
36
+ @after_change_callbacks.each(&:call)
37
+ end
38
+
39
+ def to_h
40
+ store.dup
41
+ end
42
+
43
+ def clear
44
+ store.clear
45
+ end
46
+
47
+ private
48
+ def store
49
+ IsolatedExecutionState[:active_support_execution_context] ||= {}
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/error_reporter"
3
4
  require "active_support/callbacks"
4
5
  require "concurrent/hash"
5
6
 
@@ -86,15 +87,32 @@ module ActiveSupport
86
87
  instance = run!
87
88
  begin
88
89
  yield
90
+ rescue => error
91
+ error_reporter.report(error, handled: false)
92
+ raise
89
93
  ensure
90
94
  instance.complete!
91
95
  end
92
96
  end
93
97
 
98
+ def self.perform # :nodoc:
99
+ instance = new
100
+ instance.run
101
+ begin
102
+ yield
103
+ ensure
104
+ instance.complete
105
+ end
106
+ end
107
+
94
108
  class << self # :nodoc:
95
109
  attr_accessor :active
96
110
  end
97
111
 
112
+ def self.error_reporter
113
+ @error_reporter ||= ActiveSupport::ErrorReporter.new
114
+ end
115
+
98
116
  def self.inherited(other) # :nodoc:
99
117
  super
100
118
  other.active = Concurrent::Hash.new
@@ -103,11 +121,15 @@ module ActiveSupport
103
121
  self.active = Concurrent::Hash.new
104
122
 
105
123
  def self.active? # :nodoc:
106
- @active[Thread.current]
124
+ @active[IsolatedExecutionState.unique_id]
107
125
  end
108
126
 
109
127
  def run! # :nodoc:
110
- self.class.active[Thread.current] = true
128
+ self.class.active[IsolatedExecutionState.unique_id] = true
129
+ run
130
+ end
131
+
132
+ def run # :nodoc:
111
133
  run_callbacks(:run)
112
134
  end
113
135
 
@@ -116,9 +138,13 @@ module ActiveSupport
116
138
  #
117
139
  # Where possible, prefer +wrap+.
118
140
  def complete!
119
- run_callbacks(:complete)
141
+ complete
120
142
  ensure
121
- self.class.active.delete Thread.current
143
+ self.class.active.delete(IsolatedExecutionState.unique_id)
144
+ end
145
+
146
+ def complete # :nodoc:
147
+ run_callbacks(:complete)
122
148
  end
123
149
 
124
150
  private
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport::Executor::TestHelper # :nodoc:
4
+ def run(...)
5
+ Rails.application.executor.perform { super }
6
+ end
7
+ end
@@ -2,6 +2,16 @@
2
2
 
3
3
  module ActiveSupport
4
4
  module ForkTracker # :nodoc:
5
+ module ModernCoreExt
6
+ def _fork
7
+ pid = super
8
+ if pid == 0
9
+ ForkTracker.check!
10
+ end
11
+ pid
12
+ end
13
+ end
14
+
5
15
  module CoreExt
6
16
  def fork(...)
7
17
  if block_given?
@@ -20,11 +30,7 @@ module ActiveSupport
20
30
 
21
31
  module CoreExtPrivate
22
32
  include CoreExt
23
-
24
- private
25
- def fork(...)
26
- super
27
- end
33
+ private :fork
28
34
  end
29
35
 
30
36
  @pid = Process.pid
@@ -32,15 +38,18 @@ module ActiveSupport
32
38
 
33
39
  class << self
34
40
  def check!
35
- if @pid != Process.pid
41
+ new_pid = Process.pid
42
+ if @pid != new_pid
36
43
  @callbacks.each(&:call)
37
- @pid = Process.pid
44
+ @pid = new_pid
38
45
  end
39
46
  end
40
47
 
41
48
  def hook!
42
- if Process.respond_to?(:fork)
43
- ::Object.prepend(CoreExtPrivate)
49
+ if Process.respond_to?(:_fork) # Ruby 3.1+
50
+ ::Process.singleton_class.prepend(ModernCoreExt)
51
+ elsif Process.respond_to?(:fork)
52
+ ::Object.prepend(CoreExtPrivate) if RUBY_VERSION < "3.0"
44
53
  ::Kernel.prepend(CoreExtPrivate)
45
54
  ::Kernel.singleton_class.prepend(CoreExt)
46
55
  ::Process.singleton_class.prepend(CoreExt)
@@ -10,7 +10,7 @@ module ActiveSupport
10
10
  MAJOR = 7
11
11
  MINOR = 0
12
12
  TINY = 0
13
- PRE = "alpha2"
13
+ PRE = "rc1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module HtmlSafeTranslation # :nodoc:
5
+ extend self
6
+
7
+ def translate(key, **options)
8
+ if html_safe_translation_key?(key)
9
+ html_safe_options = html_escape_translation_options(options)
10
+ translation = I18n.translate(key, **html_safe_options)
11
+ html_safe_translation(translation)
12
+ else
13
+ I18n.translate(key, **options)
14
+ end
15
+ end
16
+
17
+ private
18
+ def html_safe_translation_key?(key)
19
+ /(?:_|\b)html\z/.match?(key)
20
+ end
21
+
22
+ def html_escape_translation_options(options)
23
+ options.each do |name, value|
24
+ unless i18n_option?(name) || (name == :count && value.is_a?(Numeric))
25
+ options[name] = ERB::Util.html_escape(value.to_s)
26
+ end
27
+ end
28
+ end
29
+
30
+ def i18n_option?(name)
31
+ (@i18n_option_names ||= I18n::RESERVED_KEYS.to_set).include?(name)
32
+ end
33
+
34
+
35
+ def html_safe_translation(translation)
36
+ if translation.respond_to?(:map)
37
+ translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
38
+ else
39
+ translation.respond_to?(:html_safe) ? translation.html_safe : translation
40
+ end
41
+ end
42
+ end
43
+ end
@@ -77,7 +77,7 @@ module I18n
77
77
 
78
78
  def self.forward_raise_on_missing_translations_config(app)
79
79
  ActiveSupport.on_load(:action_view) do
80
- self.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
80
+ ActionView::Helpers::TranslationHelper.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
81
81
  end
82
82
 
83
83
  ActiveSupport.on_load(:action_controller) do
@@ -222,15 +222,24 @@ module ActiveSupport
222
222
  # Clears the loaded inflections within a given scope (default is
223
223
  # <tt>:all</tt>). Give the scope as a symbol of the inflection type, the
224
224
  # options are: <tt>:plurals</tt>, <tt>:singulars</tt>, <tt>:uncountables</tt>,
225
- # <tt>:humans</tt>.
225
+ # <tt>:humans</tt>, <tt>:acronyms</tt>.
226
226
  #
227
227
  # clear :all
228
228
  # clear :plurals
229
229
  def clear(scope = :all)
230
230
  case scope
231
231
  when :all
232
- @plurals, @singulars, @uncountables, @humans = [], [], Uncountables.new, []
233
- else
232
+ clear(:acronyms)
233
+ clear(:plurals)
234
+ clear(:singulars)
235
+ clear(:uncountables)
236
+ clear(:humans)
237
+ when :acronyms
238
+ @acronyms = {}
239
+ define_acronym_regex_patterns
240
+ when :uncountables
241
+ @uncountables = Uncountables.new
242
+ when :plurals, :singulars, :humans
234
243
  instance_variable_set "@#{scope}", []
235
244
  end
236
245
  end
@@ -97,7 +97,7 @@ module ActiveSupport
97
97
  return camel_cased_word.to_s unless /[A-Z-]|::/.match?(camel_cased_word)
98
98
  word = camel_cased_word.to_s.gsub("::", "/")
99
99
  word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
100
- word.gsub!(/([A-Z\d]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
100
+ word.gsub!(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
101
101
  word.tr!("-", "_")
102
102
  word.downcase!
103
103
  word
@@ -109,7 +109,7 @@ module ActiveSupport
109
109
  #
110
110
  # * Applies human inflection rules to the argument.
111
111
  # * Deletes leading underscores, if any.
112
- # * Removes a "_id" suffix if present.
112
+ # * Removes an "_id" suffix if present.
113
113
  # * Replaces underscores with spaces, if any.
114
114
  # * Downcases all words except acronyms.
115
115
  # * Capitalizes the first word.
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fiber"
4
+
5
+ module ActiveSupport
6
+ module IsolatedExecutionState # :nodoc:
7
+ @isolation_level = :thread
8
+
9
+ Thread.attr_accessor :active_support_execution_state
10
+ Fiber.attr_accessor :active_support_execution_state
11
+
12
+ class << self
13
+ attr_reader :isolation_level
14
+
15
+ def isolation_level=(level)
16
+ unless %i(thread fiber).include?(level)
17
+ raise ArgumentError, "isolation_level must be `:thread` or `:fiber`, got: `#{level.inspect}`"
18
+ end
19
+
20
+ if level != isolation_level
21
+ clear
22
+ singleton_class.alias_method(:current, "current_#{level}")
23
+ singleton_class.send(:private, :current)
24
+ @isolation_level = level
25
+ end
26
+ end
27
+
28
+ def unique_id
29
+ self[:__id__] ||= Object.new
30
+ end
31
+
32
+ def [](key)
33
+ current[key]
34
+ end
35
+
36
+ def []=(key, value)
37
+ current[key] = value
38
+ end
39
+
40
+ def clear
41
+ current.clear
42
+ end
43
+
44
+ private
45
+ def current_thread
46
+ Thread.current.active_support_execution_state ||= {}
47
+ end
48
+
49
+ def current_fiber
50
+ Fiber.current.active_support_execution_state ||= {}
51
+ end
52
+
53
+ alias_method :current, :current_thread
54
+ end
55
+ end
56
+ end
@@ -18,8 +18,7 @@ module ActiveSupport
18
18
  end
19
19
 
20
20
  def local_level
21
- # Note: Thread#[] is fiber-local
22
- Thread.current[:logger_thread_safe_level]
21
+ IsolatedExecutionState[:logger_thread_safe_level]
23
22
  end
24
23
 
25
24
  def local_level=(level)
@@ -31,7 +30,7 @@ module ActiveSupport
31
30
  else
32
31
  raise ArgumentError, "Invalid log level: #{level.inspect}"
33
32
  end
34
- Thread.current[:logger_thread_safe_level] = level
33
+ IsolatedExecutionState[:logger_thread_safe_level] = level
35
34
  end
36
35
 
37
36
  def level
@@ -22,6 +22,11 @@ module ActiveSupport
22
22
  # crypt = ActiveSupport::MessageEncryptor.new(key) # => #<ActiveSupport::MessageEncryptor ...>
23
23
  # encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
24
24
  # crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
25
+ # The +decrypt_and_verify+ method will raise an
26
+ # <tt>ActiveSupport::MessageEncryptor::InvalidMessage</tt> exception if the data
27
+ # provided cannot be decrypted or verified.
28
+ #
29
+ # crypt.decrypt_and_verify('not encrypted data') # => ActiveSupport::MessageEncryptor::InvalidMessage
25
30
  #
26
31
  # === Confining messages to a specific purpose
27
32
  #
@@ -8,18 +8,6 @@ module ActiveSupport
8
8
  # The Unicode version that is supported by the implementation
9
9
  UNICODE_VERSION = RbConfig::CONFIG["UNICODE_VERSION"]
10
10
 
11
- def default_normalization_form
12
- ActiveSupport::Deprecation.warn(
13
- "ActiveSupport::Multibyte::Unicode.default_normalization_form is deprecated and will be removed in Rails 7.0."
14
- )
15
- end
16
-
17
- def default_normalization_form=(_)
18
- ActiveSupport::Deprecation.warn(
19
- "ActiveSupport::Multibyte::Unicode.default_normalization_form= is deprecated and will be removed in Rails 7.0."
20
- )
21
- end
22
-
23
11
  # Decompose composed characters to the decomposed form.
24
12
  def decompose(type, codepoints)
25
13
  if type == :compatibility
@@ -7,6 +7,16 @@ require "active_support/core_ext/object/try"
7
7
 
8
8
  module ActiveSupport
9
9
  module Notifications
10
+ class InstrumentationSubscriberError < RuntimeError
11
+ attr_reader :exceptions
12
+
13
+ def initialize(exceptions)
14
+ @exceptions = exceptions
15
+ exception_class_names = exceptions.map { |e| e.class.name }
16
+ super "Exception(s) occurred within instrumentation subscribers: #{exception_class_names.join(', ')}"
17
+ end
18
+ end
19
+
10
20
  # This is a default queue implementation that ships with Notifications.
11
21
  # It just pushes events to all registered log subscribers.
12
22
  #
@@ -59,19 +69,40 @@ module ActiveSupport
59
69
  end
60
70
 
61
71
  def start(name, id, payload)
62
- listeners_for(name).each { |s| s.start(name, id, payload) }
72
+ iterate_guarding_exceptions(listeners_for(name)) { |s| s.start(name, id, payload) }
63
73
  end
64
74
 
65
75
  def finish(name, id, payload, listeners = listeners_for(name))
66
- listeners.each { |s| s.finish(name, id, payload) }
76
+ iterate_guarding_exceptions(listeners) { |s| s.finish(name, id, payload) }
67
77
  end
68
78
 
69
79
  def publish(name, *args)
70
- listeners_for(name).each { |s| s.publish(name, *args) }
80
+ iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name, *args) }
71
81
  end
72
82
 
73
83
  def publish_event(event)
74
- listeners_for(event.name).each { |s| s.publish_event(event) }
84
+ iterate_guarding_exceptions(listeners_for(event.name)) { |s| s.publish_event(event) }
85
+ end
86
+
87
+ def iterate_guarding_exceptions(listeners)
88
+ exceptions = nil
89
+
90
+ listeners.each do |s|
91
+ yield s
92
+ rescue Exception => e
93
+ exceptions ||= []
94
+ exceptions << e
95
+ end
96
+
97
+ if exceptions
98
+ if exceptions.size == 1
99
+ raise exceptions.first
100
+ else
101
+ raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
102
+ end
103
+ end
104
+
105
+ listeners
75
106
  end
76
107
 
77
108
  def listeners_for(name)
@@ -108,23 +139,20 @@ module ActiveSupport
108
139
  end
109
140
  end
110
141
 
111
- wrap_all pattern, subscriber_class.new(pattern, listener)
112
- end
113
-
114
- def self.wrap_all(pattern, subscriber)
115
- unless pattern
116
- AllMessages.new(subscriber)
117
- else
118
- subscriber
119
- end
142
+ subscriber_class.new(pattern, listener)
120
143
  end
121
144
 
122
145
  class Matcher # :nodoc:
123
146
  attr_reader :pattern, :exclusions
124
147
 
125
148
  def self.wrap(pattern)
126
- return pattern if String === pattern
127
- new(pattern)
149
+ if String === pattern
150
+ pattern
151
+ elsif pattern.nil?
152
+ AllMessages.new
153
+ else
154
+ new(pattern)
155
+ end
128
156
  end
129
157
 
130
158
  def initialize(pattern)
@@ -139,6 +167,16 @@ module ActiveSupport
139
167
  def ===(name)
140
168
  pattern === name && !exclusions.include?(name)
141
169
  end
170
+
171
+ class AllMessages
172
+ def ===(name)
173
+ true
174
+ end
175
+
176
+ def unsubscribe!(*)
177
+ false
178
+ end
179
+ end
142
180
  end
143
181
 
144
182
  class Evented # :nodoc:
@@ -177,10 +215,6 @@ module ActiveSupport
177
215
  pattern === name
178
216
  end
179
217
 
180
- def matches?(name)
181
- pattern && pattern === name
182
- end
183
-
184
218
  def unsubscribe!(name)
185
219
  pattern.unsubscribe!(name)
186
220
  end
@@ -192,12 +226,12 @@ module ActiveSupport
192
226
  end
193
227
 
194
228
  def start(name, id, payload)
195
- timestack = Thread.current[:_timestack] ||= []
229
+ timestack = IsolatedExecutionState[:_timestack] ||= []
196
230
  timestack.push Time.now
197
231
  end
198
232
 
199
233
  def finish(name, id, payload)
200
- timestack = Thread.current[:_timestack]
234
+ timestack = IsolatedExecutionState[:_timestack]
201
235
  started = timestack.pop
202
236
  @delegate.call(name, started, Time.now, id, payload)
203
237
  end
@@ -209,27 +243,27 @@ module ActiveSupport
209
243
  end
210
244
 
211
245
  def start(name, id, payload)
212
- timestack = Thread.current[:_timestack_monotonic] ||= []
213
- timestack.push Concurrent.monotonic_time
246
+ timestack = IsolatedExecutionState[:_timestack_monotonic] ||= []
247
+ timestack.push Process.clock_gettime(Process::CLOCK_MONOTONIC)
214
248
  end
215
249
 
216
250
  def finish(name, id, payload)
217
- timestack = Thread.current[:_timestack_monotonic]
251
+ timestack = IsolatedExecutionState[:_timestack_monotonic]
218
252
  started = timestack.pop
219
- @delegate.call(name, started, Concurrent.monotonic_time, id, payload)
253
+ @delegate.call(name, started, Process.clock_gettime(Process::CLOCK_MONOTONIC), id, payload)
220
254
  end
221
255
  end
222
256
 
223
257
  class EventObject < Evented
224
258
  def start(name, id, payload)
225
- stack = Thread.current[:_event_stack] ||= []
259
+ stack = IsolatedExecutionState[:_event_stack] ||= []
226
260
  event = build_event name, id, payload
227
261
  event.start!
228
262
  stack.push event
229
263
  end
230
264
 
231
265
  def finish(name, id, payload)
232
- stack = Thread.current[:_event_stack]
266
+ stack = IsolatedExecutionState[:_event_stack]
233
267
  event = stack.pop
234
268
  event.payload = payload
235
269
  event.finish!
@@ -245,34 +279,6 @@ module ActiveSupport
245
279
  ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
246
280
  end
247
281
  end
248
-
249
- class AllMessages # :nodoc:
250
- def initialize(delegate)
251
- @delegate = delegate
252
- end
253
-
254
- def start(name, id, payload)
255
- @delegate.start name, id, payload
256
- end
257
-
258
- def finish(name, id, payload)
259
- @delegate.finish name, id, payload
260
- end
261
-
262
- def publish(name, *args)
263
- @delegate.publish name, *args
264
- end
265
-
266
- def subscribed_to?(name)
267
- true
268
- end
269
-
270
- def unsubscribe!(*)
271
- false
272
- end
273
-
274
- alias :matches? :===
275
- end
276
282
  end
277
283
  end
278
284
  end
@@ -62,12 +62,12 @@ module ActiveSupport
62
62
  def initialize(name, start, ending, transaction_id, payload)
63
63
  @name = name
64
64
  @payload = payload.dup
65
- @time = start
65
+ @time = start ? start.to_f * 1_000.0 : start
66
66
  @transaction_id = transaction_id
67
- @end = ending
67
+ @end = ending ? ending.to_f * 1_000.0 : ending
68
68
  @children = []
69
- @cpu_time_start = 0
70
- @cpu_time_finish = 0
69
+ @cpu_time_start = 0.0
70
+ @cpu_time_finish = 0.0
71
71
  @allocation_count_start = 0
72
72
  @allocation_count_finish = 0
73
73
  end
@@ -102,7 +102,7 @@ module ActiveSupport
102
102
  # Returns the CPU time (in milliseconds) passed since the call to
103
103
  # +start!+ and the call to +finish!+
104
104
  def cpu_time
105
- (@cpu_time_finish - @cpu_time_start) * 1000
105
+ @cpu_time_finish - @cpu_time_start
106
106
  end
107
107
 
108
108
  # Returns the idle time time (in milliseconds) passed since the call to
@@ -130,7 +130,7 @@ module ActiveSupport
130
130
  #
131
131
  # @event.duration # => 1000.138
132
132
  def duration
133
- 1000.0 * (self.end - time)
133
+ self.end - time
134
134
  end
135
135
 
136
136
  def <<(event)
@@ -143,28 +143,28 @@ module ActiveSupport
143
143
 
144
144
  private
145
145
  def now
146
- Concurrent.monotonic_time
146
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
147
147
  end
148
148
 
149
149
  begin
150
- Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
150
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
151
151
 
152
152
  def now_cpu
153
- Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
153
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
154
154
  end
155
155
  rescue
156
- def now_cpu
157
- 0
156
+ def now_cpu # rubocop:disable Lint/DuplicateMethods
157
+ 0.0
158
158
  end
159
159
  end
160
160
 
161
- if defined?(JRUBY_VERSION)
161
+ if GC.stat.key?(:total_allocated_objects)
162
162
  def now_allocations
163
- 0
163
+ GC.stat(:total_allocated_objects)
164
164
  end
165
- else
165
+ else # Likely on JRuby, TruffleRuby
166
166
  def now_allocations
167
- GC.stat :total_allocated_objects
167
+ 0
168
168
  end
169
169
  end
170
170
  end