mirror of https://github.com/rails/rails
Define the new start_transaction.active_record event
This commit is contained in:
parent
0733ab5118
commit
f64a4134df
|
@ -91,7 +91,9 @@ module ActiveRecord
|
|||
raise InstrumentationAlreadyStartedError.new("Called start on an already started transaction") if @started
|
||||
@started = true
|
||||
|
||||
@payload = @base_payload.dup
|
||||
ActiveSupport::Notifications.instrument("start_transaction.active_record", @base_payload)
|
||||
|
||||
@payload = @base_payload.dup # We dup because the payload for a given event is mutated later to add the outcome.
|
||||
@handle = ActiveSupport::Notifications.instrumenter.build_handle("transaction.active_record", @payload)
|
||||
@handle.start
|
||||
end
|
||||
|
|
|
@ -7,6 +7,62 @@ class TransactionInstrumentationTest < ActiveRecord::TestCase
|
|||
self.use_transactional_tests = false
|
||||
fixtures :topics
|
||||
|
||||
def test_start_transaction_is_triggered_when_the_transaction_is_materialized
|
||||
transactions = []
|
||||
subscriber = ActiveSupport::Notifications.subscribe("start_transaction.active_record") do |event|
|
||||
assert event.payload[:connection]
|
||||
transactions << event.payload[:transaction]
|
||||
end
|
||||
|
||||
Topic.transaction do |transaction|
|
||||
assert_empty transactions # A transaction call, per se, does not trigger the event.
|
||||
topics(:first).touch
|
||||
assert_equal [transaction], transactions
|
||||
end
|
||||
ensure
|
||||
ActiveSupport::Notifications.unsubscribe(subscriber)
|
||||
end
|
||||
|
||||
def test_start_transaction_is_not_triggered_for_ordinary_nested_calls
|
||||
transactions = []
|
||||
subscriber = ActiveSupport::Notifications.subscribe("start_transaction.active_record") do |event|
|
||||
assert event.payload[:connection]
|
||||
transactions << event.payload[:transaction]
|
||||
end
|
||||
|
||||
Topic.transaction do |t1|
|
||||
topics(:first).touch
|
||||
assert_equal [t1], transactions
|
||||
|
||||
Topic.transaction do |_t2|
|
||||
topics(:first).touch
|
||||
assert_equal [t1], transactions
|
||||
end
|
||||
end
|
||||
ensure
|
||||
ActiveSupport::Notifications.unsubscribe(subscriber)
|
||||
end
|
||||
|
||||
def test_start_transaction_is_triggered_for_requires_new
|
||||
transactions = []
|
||||
subscriber = ActiveSupport::Notifications.subscribe("start_transaction.active_record") do |event|
|
||||
assert event.payload[:connection]
|
||||
transactions << event.payload[:transaction]
|
||||
end
|
||||
|
||||
Topic.transaction do |t1|
|
||||
topics(:first).touch
|
||||
assert_equal [t1], transactions
|
||||
|
||||
Topic.transaction(requires_new: true) do |t2|
|
||||
topics(:first).touch
|
||||
assert_equal [t1, t2], transactions
|
||||
end
|
||||
end
|
||||
ensure
|
||||
ActiveSupport::Notifications.unsubscribe(subscriber)
|
||||
end
|
||||
|
||||
def test_transaction_instrumentation_on_commit
|
||||
topic = topics(:fifth)
|
||||
|
||||
|
|
|
@ -410,9 +410,56 @@ This event is only emitted when [`config.active_record.action_on_strict_loading_
|
|||
}
|
||||
```
|
||||
|
||||
#### `start_transaction.active_record`
|
||||
|
||||
This event is emitted when a transaction has been started.
|
||||
|
||||
| Key | Value |
|
||||
| -------------------- | ---------------------------------------------------- |
|
||||
| `:transaction` | Transaction object |
|
||||
| `:connection` | Connection object |
|
||||
|
||||
Please, note that Active Record does not create the actual database transaction
|
||||
until needed:
|
||||
|
||||
```ruby
|
||||
ActiveRecord::Base.transaction do
|
||||
# We are inside the block, but no event has been triggered yet.
|
||||
|
||||
# The following line makes Active Record start the transaction.
|
||||
User.count # Event fired here.
|
||||
end
|
||||
```
|
||||
|
||||
Remember that ordinary nested calls do not create new transactions:
|
||||
|
||||
```ruby
|
||||
ActiveRecord::Base.transaction do |t1|
|
||||
User.count # Fires an event for t1.
|
||||
ActiveRecord::Base.transaction do |t2|
|
||||
# The next line fires no event for t2, because the only
|
||||
# real database transaction in this example is t1.
|
||||
User.first.touch
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
However, if `requires_new: true` is passed, you get an event for the nested
|
||||
transaction too. This might be a savepoint under the hood:
|
||||
|
||||
```ruby
|
||||
ActiveRecord::Base.transaction do |t1|
|
||||
User.count # Fires an event for t1.
|
||||
ActiveRecord::Base.transaction(requires_new: true) do |t2|
|
||||
User.first.touch # Fires an event for t2.
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
#### `transaction.active_record`
|
||||
|
||||
This event is emmited for every transaction to the database.
|
||||
This event is emitted when a database transaction finishes. The state of the
|
||||
transaction can be found in the `:outcome` key.
|
||||
|
||||
| Key | Value |
|
||||
| -------------------- | ---------------------------------------------------- |
|
||||
|
@ -420,10 +467,9 @@ This event is emmited for every transaction to the database.
|
|||
| `:outcome` | `:commit`, `:rollback`, `:restart`, or `:incomplete` |
|
||||
| `:connection` | Connection object |
|
||||
|
||||
Please note that at this point the transaction has been finished, and its state
|
||||
is in the `:outcome` key. In practice, you cannot do much with the transaction
|
||||
object, but it may still be helpful for tracing database activity. For example,
|
||||
by tracking `transaction.uuid`.
|
||||
In practice, you cannot do much with the transaction object, but it may still be
|
||||
helpful for tracing database activity. For example, by tracking
|
||||
`transaction.uuid`.
|
||||
|
||||
### Action Mailer
|
||||
|
||||
|
|
Loading…
Reference in New Issue