Ref: https://github.com/rails/rails/issues/43472
We swallow these exceptions because it makes sense for a cache to
fallback to a cache miss in case of transcient failures.
However there's value in reporting these to the application
owners so that they can be alerted that something undesirable happened.
* This works whether the Ruby implementation raises or uses a Hash with
a default of 0 to represent unknown keys (like TruffleRuby) and so
this is more portable.
* Also avoids an extra exception on JRuby.
This module has been soft deprecated for a long time, but since
it was used internally it wasn't throwing deprecation warnings.
Now we can throw a deprecation warning.
Ref: https://github.com/rails/rails/pull/43596
This allow users to declare wether their unit of work is isolated by
fibers or by threads.
`PerThreadRegistry` and `thread_mattr_accessor` were intentionally left
out as they require documentation change. I'll submit them in separate
pull requests.
Many places in Active Support and Rails in general use `Thread.current#[]`
to store "request (or job) local data". This often cause problems with
`Enumerator` because it runs in a different fiber.
On the other hand, some places migrated to `Thread#thread_variable_get`
which cause issues with fiber based servers (`falcon`).
Based on this, I believe the isolation level should be an application
configuration.
For backward compatibility it could ship with `:fiber` isolation as a default
but longer term :thread would make more sense as it would work fine for
all deployment targets except falcon.
Ref: https://github.com/rails/rails/pull/38905
Ref: https://github.com/rails/rails/pull/39428
Ref: https://github.com/rails/rails/pull/34495
(and possibly many others)
Fix: https://github.com/rails/rails/issues/43472
The reporter is held by the executor, but the `Rails` module provides a
nicer `Rails.error` shortcut.
For ease of use, two block based specialized methods are exposed.
`handle`, which swallow errors and forward them to the subscribers:
```ruby
Rails.error.handle do
1 + '1' # raises TypeError
end
1 + 1 # This will be executed
```
`record`, which forward the errors to the subscribes but let it
continue rewinding the call stack:
```ruby
Rails.error.record do
1 + '1' # raises TypeError
end
1 + 1 # This won't be executed.
```
For cases where the blocked based API isn't suitable, the lower level
`report` method can be used:
```ruby
Rails.error.report(error, handled: true / false)
```
Since the test are skipped when Redis | Memcache are not reacheable two
instance variables are not initialized properly but used on teardown
blocks, having warnings about undeclared variables:
- instance variable @cache not initialized (redis cache store)
- instance variable @_stores not initialized (memcache store)
Historically `Date._iso8601(nil)` returns `{}`.
But in these versions it raises a `TypeError` changing the exception type
of `ActiveSupport::TimeZone#iso8601(nil)`, which may break some applications.
I'm working on a standardized error reporting interface
(https://github.com/rails/rails/issues/43472) and it has the same need
for a `context` than Active Record's query logs.
Just like query logs, when reporting an error you want to know what the
current controller or job is, etc.
So by extracting it we can allow both API to use the same store.
Ref: https://github.com/rails/rails/pull/43282
Ref: https://github.com/rails/rails/pull/43561
It can be legitimate for subscriber to want to bubble up some exception
to the caller, so wrapping it change the exception class which might break
the calling code expecting a specific error.
We can minimize this by only using InstrumentationSubscriberError
when more than one subscriber raised.
The bulk of the optimization is to generate code rather than use
`define_method` with a closure.
```
Warming up --------------------------------------
original 207.468k i/100ms
code-generator 340.849k i/100ms
Calculating -------------------------------------
original 2.127M (± 1.1%) i/s - 10.788M in 5.073860s
code-generator 3.426M (± 0.9%) i/s - 17.383M in 5.073965s
Comparison:
code-generator: 3426241.0 i/s
original: 2126539.2 i/s - 1.61x (± 0.00) slower
```
```ruby
require 'benchmark/ips'
require 'active_support/all'
class Original < ActiveSupport::CurrentAttributes
attribute :foo
end
class CodeGen < ActiveSupport::CurrentAttributes
class << self
def attribute(*names)
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
names.each do |name|
owner.define_cached_method(name, namespace: :current_attributes) do |batch|
batch <<
"def #{name}" <<
"attributes[:#{name}]" <<
"end"
end
owner.define_cached_method("#{name}=", namespace: :current_attributes) do |batch|
batch <<
"def #{name}=(value)" <<
"attributes[:#{name}] = value" <<
"end"
end
end
end
ActiveSupport::CodeGenerator.batch(singleton_class, __FILE__, __LINE__) do |owner|
names.each do |name|
owner.define_cached_method(name, namespace: :current_attributes_delegation) do |batch|
batch <<
"def #{name}" <<
"instance.#{name}" <<
"end"
end
owner.define_cached_method("#{name}=", namespace: :current_attributes_delegation) do |batch|
batch <<
"def #{name}=(value)" <<
"instance.#{name} = value" <<
"end"
end
end
end
end
end
attribute :foo
end
Benchmark.ips do |x|
x.report('original') { Original.foo }
x.report('code-generator') { CodeGen.foo }
x.compare!
end
```
It's `Rails.application.executor.wrap` that is responsible for
clearing request/job local state such as `CurrentAttributes`.
Instead of including an ad hoc helper to clear `CurrentAttributes` it's
better to run the executor so we properly clear other states as well.
However it means all executor hooks now need to be re-entrant.
It's `Rails.application.executor.wrap` that is responsible for
clearing request/job local state such as `CurrentAttributes`.
Instead of including an ad hoc helper to clear `CurrentAttributes` it's
better to run the executor so we properly clear other states as well.
Updates the `Digest::UUID.uuid_from_hash` to return the correct UUID values
for namespace IDs that are different from the ones provided on `Digest::UUID`.
- The new behavior will be enabled by setting the
`config.active_support.use_rfc4122_namespaced_uuids` option to `true`
and is the default for new apps.
- The old behavior is the default for upgraded apps and will output a
deprecation warning every time a value that is different than one of
the constants defined on the `Digest::UUID` extension is used as the
namespace ID.
Fixes#37681.
Unless you are on a Ruby older than 2.3 (or some very old JRuby)
`Concurrent.monotonic_time` is just `Process.clock_gettime(Process::CLOCK_MONOTONIC)`.
So might as well skip the extra method call, and more importantly
it allows in many cases to pass the scale as second argument and save some
floating point multiplication.
This module will be a private module in Active Support, this way
if we need to change the behavior of translate in controllers or
views don't forget to change in the other one.
The word "Crazy" has long been associated with mental illness. While
there may be other dictionary definitions, it's difficult for some of us
to separate the word from the stigmatization, gaslighting, and bullying
that often comes along with it.
This commit replaces instances of the word with various alternatives. I
find most of these more focused and descriptive than what we had before.
Since the module isn't included anywhere and is purely static
there iss no point using `mattr_accessor`, which define instance
accessors and other extra overhead.
Regular `attr_accessor` does the job just fine.
Use Kernel::Float(..., exceptions:false) instead of a rescue block in
ActionView::Helpers::NumberHelper and
ActiveSupport::NumberHelper::NumberConverter to slightly improve
performance.
Also remove documentation that incorrectly states
ActiveSupport::NumberHelper supports the `raise:` option.
The descendants tracker is a generic tracker that you can use anywhere.
In particular, outside Rails applications.
Should provide API to clear only a subset of classes, but in my view
should know nothing about autoloading. That is a concern of client code.