Include the current transaction in sql.active_record event payloads

This commit is contained in:
Xavier Noria 2024-05-31 13:05:20 +02:00
parent bc56661a3d
commit c16d552c32
5 changed files with 75 additions and 0 deletions

View File

@ -277,6 +277,7 @@ module ActiveRecord
type_casted_binds: -> { type_casted_binds(binds) }, type_casted_binds: -> { type_casted_binds(binds) },
name: name, name: name,
connection: self, connection: self,
transaction: current_transaction,
cached: true cached: true
} }
end end

View File

@ -1118,6 +1118,7 @@ module ActiveRecord
statement_name: statement_name, statement_name: statement_name,
async: async, async: async,
connection: self, connection: self,
transaction: current_transaction,
row_count: 0, row_count: 0,
&block &block
) )

View File

@ -170,5 +170,36 @@ module ActiveRecord
ensure ensure
ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
end end
def test_payload_with_implicit_transaction
expected_transaction = Book.current_transaction
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event|
if event.payload[:name] == "Book Count"
assert_same expected_transaction, event.payload[:transaction]
end
end
Book.count
ensure
ActiveSupport::Notifications.unsubscribe(subscriber)
end
def test_payload_with_explicit_transaction
expected_transaction = nil
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event|
if event.payload[:name] == "Book Load"
assert_same expected_transaction, event.payload[:transaction]
end
end
Book.transaction do |transaction|
expected_transaction = transaction
Book.first
end
ensure
ActiveSupport::Notifications.unsubscribe(subscriber)
end
end end
end end

View File

@ -1067,4 +1067,40 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
assert_equal @connection_1, @connection_2 assert_equal @connection_1, @connection_2
end end
test "payload with implicit transaction" do
expected_transaction = Task.current_transaction
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event|
if event.payload[:cached]
assert_same expected_transaction, event.payload[:transaction]
end
end
Task.cache do
2.times { Task.count }
end
ensure
ActiveSupport::Notifications.unsubscribe(subscriber)
end
test "payload with explicit transaction" do
expected_transaction = nil
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event|
if event.payload[:cached]
assert_same expected_transaction, event.payload[:transaction]
end
end
Task.transaction do |transaction|
expected_transaction = transaction
Task.cache do
2.times { Task.count }
end
end
ensure
ActiveSupport::Notifications.unsubscribe(subscriber)
end
end end

View File

@ -360,6 +360,7 @@ The `:cache_hits` key is only included if the collection is rendered with `cache
| `:sql` | SQL statement | | `:sql` | SQL statement |
| `:name` | Name of the operation | | `:name` | Name of the operation |
| `:connection` | Connection object | | `:connection` | Connection object |
| `:transaction` | Current transaction |
| `:binds` | Bind parameters | | `:binds` | Bind parameters |
| `:type_casted_binds` | Typecasted bind parameters | | `:type_casted_binds` | Typecasted bind parameters |
| `:statement_name` | SQL Statement name | | `:statement_name` | SQL Statement name |
@ -374,6 +375,7 @@ Adapters may add their own data as well.
sql: "SELECT \"posts\".* FROM \"posts\" ", sql: "SELECT \"posts\".* FROM \"posts\" ",
name: "Post Load", name: "Post Load",
connection: <ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x00007f9f7a838850>, connection: <ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x00007f9f7a838850>,
transaction: <ActiveRecord::ConnectionAdapters::RealTransaction:0x0000000121b5d3e0>
binds: [<ActiveModel::Attribute::WithCastValue:0x00007fe19d15dc00>], binds: [<ActiveModel::Attribute::WithCastValue:0x00007fe19d15dc00>],
type_casted_binds: [11], type_casted_binds: [11],
statement_name: nil, statement_name: nil,
@ -381,6 +383,10 @@ Adapters may add their own data as well.
} }
``` ```
If there is no transaction started at the moment, `:transaction` has a null
object with UUID `00000000-0000-0000-0000-000000000000` (the nil UUID). This may
happen, for example, issuing a `SELECT` not wrapped in a transaction.
#### `strict_loading_violation.active_record` #### `strict_loading_violation.active_record`
This event is only emitted when [`config.active_record.action_on_strict_loading_violation`][] is set to `:log`. This event is only emitted when [`config.active_record.action_on_strict_loading_violation`][] is set to `:log`.