2024 年 4 月 5 日 星期五

将作业排入队列推迟到事务提交之后,呈现日志中的查询数,等等

Wojtek 发帖

大家好,我是 Wojtek,我来介绍本周的更新。

2024 年版 Rails World 网站现已上线
4 月份门票开始售卖。

允许在记录外注册事务回调
ActiveRecord::Base.transaction 现在产生一个 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

自动延迟活动作业排队,直到提交之后
使用活动作业的常见错误是在事务内排入队列作业,导致另一个进程在事务提交之前选择并运行这些作业,从而导致各种错误。

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

现在,活动作业会自动将排入队列延迟到事务提交之后,如果事务回滚,将会放弃该作业。

各种队列实现可以选择禁用此行为,而用户可以禁用该行为或按作业强制执行该行为。

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

在模板呈现检测中添加查询数
通常需要快速了解当前操作生成了多少 SQL 查询。例如,快速检查是否已解决 N+1 问题,或者缓存是否有效减少了查询数等。可以通过检查日志和计算查询数来手动执行此操作,但是对于包含数十到数百个 SQL 查询的大型操作,这不是一项简单的任务。

# 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 复制过滤器和静音器
先前复制时仍在共享内部静音器和过滤器数组,导致状态泄漏。

您可以在此处查看所有更改的列表。上周,共有16 位贡献者为 Rails 代码库做出了贡献!

敬请期待下次更新!

订阅,接收最新内容通过邮件发送至您的邮箱。