2024年4月5日,星期五

将作业入队推迟到事务提交后,在渲染日志中统计查询数等等

作者:Wojtek

你好,我是Wojtek (Wojtek),正在探索本周的变更。

Rails World 2024 版网站现已上线
门票将于4月开始销售。

允许在记录外部注册事务回调
ActiveRecord::Base.transaction 现在会 yields 一个 ActiveRecord::Transaction 对象,允许在其上注册回调。

Article.transaction do |transaction|
  article.update(published: true)
  transaction.after_commit do
    PublishNotificationMailer.with(article: article).deliver_later
  end
end

添加了 ActiveRecord::Base.current_transaction,也允许在其上注册回调。

Article.current_transaction.after_commit do
  PublishNotificationMailer.with(article: article).deliver_later
end

添加 ActiveRecord.after_all_transactions_commit 回调。

对于可能在事务内部或外部运行并需要在状态更改正确持久化后执行工作的代码非常有用。

def publish_article(article)
  article.update(published: true)
  ActiveRecord.after_all_transactions_commit do
    PublishNotificationMailer.with(article: article).deliver_later
  end
end

自动将 Active Job 入队推迟到提交后
Active Job 的一个常见错误是在事务内部入队作业,这可能导致它们在事务提交之前被另一个进程拾取并运行,从而导致各种错误。

Topic.transaction do
  topic = Topic.create
  NewTopicNotificationJob.perform_later(topic)
end

现在 Active Job 将自动将入队推迟到事务提交之后,并在事务回滚时丢弃该作业。

各种队列实现可以选择禁用此行为,用户也可以禁用它,或者在每个作业的基础上强制启用它

class NewTopicNotificationJob < ApplicationJob
  self.enqueue_after_transaction_commit = :never # or :always or :default
end

在模板渲染的instrumentation中添加查询数
通常需要快速查看当前action产生了多少SQL查询。例如,快速检查 N+1 问题是否已解决,或者缓存是否正常工作,从而减少查询数量等等。这可以通过手动检查日志并计算查询数量来完成,但对于有几十到几百个 SQL 查询的大型action来说,这不是一项简单的任务。

# Before
Completed 200 OK in 3804ms (Views: 41.0ms | ActiveRecord: 33.5ms | Allocations: 112788)
# After
Completed 200 OK in 3804ms (Views: 41.0ms | ActiveRecord: 33.5ms (2 queries, 1 cached) | Allocations: 112788)

添加在回填期间忽略计数缓存列的能力
在现有的大型表上开始使用计数缓存可能会很麻烦,因为列值必须与列添加分开回填(以避免长时间锁定表),并且在*:counter_cache*使用之前(否则像*size/any?*这样在内部使用计数缓存的方法可能会产生不正确的结果)。人们通常在引入关联的计数缓存配置之前,在回填期间使用数据库触发器或子关联上的回调。

现在,为了安全地回填列,同时保持该列与添加/删除的子记录同步更新,请使用

class Comment < ApplicationRecord
  belongs_to :post, counter_cache: { active: false }
end

当计数缓存未“激活”时,*size/any?*等方法将不会使用它,而是直接从数据库获取结果。在计数缓存列回填完成后,只需从计数缓存定义中删除*$\{ active: false }*部分,它将现在被上述方法使用。

在运行测试时重试可操作错误
允许重试在运行测试时遇到的可操作错误。此功能仅在交互式终端上可用。

当数据库报告无效版本时引发命名异常
当 MySQL 数据库返回无效版本字符串时,现在将引发 ActiveRecord::ActiveRecordError 错误。

使 ActiveSupport::BacktraceCleaner 在 dup 和 clone 时复制过滤器和 silencer
以前,复制仍然会共享内部的 silencer 和过滤器数组,导致状态泄露。

您可以在这里查看所有更改的完整列表:here 上周有 16 位贡献者为 Rails 代码库做出了贡献!

下次再见!

订阅以通过邮件获取这些更新。