PERF: optimize GitHub PR onebox rebaking (#36739)

Previously, when rebaking posts containing GitHub PR oneboxes, we passed
`invalidate_oneboxes: true` to `rebake!` which would re-fetch the onebox
during cooking. This meant each post independently fetched the same PR
data from GitHub.

Now we:

1. Fetch and cache the onebox once upfront via `Oneboxer.preview`
2. Use the new `skip_publish_rebaked_changes` parameter to prevent
publishing intermediate states, without triggering onebox re-fetches
3. Filter posts by `cooked LIKE '%githubpullrequest%'` in SQL rather
than fetching all linked posts and filtering in Ruby

The new `skip_publish_rebaked_changes` parameter on `Post#rebake!`
allows callers to skip the `:rebaked` publish without triggering onebox
invalidation, which is useful when the caller has already refreshed the
cache separately.
This commit is contained in:
Régis Hanol
2025-12-17 12:06:16 +01:00
committed by GitHub
parent dcd58c419d
commit 67985bff52
4 changed files with 42 additions and 35 deletions
@@ -5,48 +5,38 @@ module Jobs
sidekiq_options queue: "low"
def execute(args)
pr_url = args[:pr_url]
return if pr_url.blank?
url = args[:pr_url]
return if url.blank?
rebake_posts(pr_url)
rebake_chat_messages(pr_url) if SiteSetting.chat_enabled
# invalidate & refresh the onebox cache for this PR URL
Oneboxer.preview(url, invalidate_oneboxes: true)
rebake_posts(url)
rebake_chat_messages(url) if SiteSetting.chat_enabled
end
private
def rebake_posts(pr_url)
post_ids =
TopicLink
.where(url: pr_url)
.or(TopicLink.where("url LIKE ?", "#{pr_url}%"))
.select(:post_id)
def rebake_posts(url)
post_ids = TopicLink.where(url:).or(TopicLink.where("url LIKE ?", "#{url}%")).select(:post_id)
Post
.where(id: post_ids)
.find_each do |post|
next unless has_github_pr_onebox?(post.cooked, pr_url)
post.rebake!(invalidate_oneboxes: true, priority: :low)
end
.where("cooked LIKE ?", "%githubpullrequest%#{url}%")
.find_each { |post| post.rebake!(priority: :low, skip_publish_rebaked_changes: true) }
end
def rebake_chat_messages(pr_url)
def rebake_chat_messages(url)
message_ids =
::Chat::MessageLink
.where(url: pr_url)
.or(::Chat::MessageLink.where("url LIKE ?", "#{pr_url}%"))
.where(url:)
.or(::Chat::MessageLink.where("url LIKE ?", "#{url}%"))
.select(:chat_message_id)
::Chat::Message
.where(id: message_ids)
.find_each do |message|
next unless has_github_pr_onebox?(message.cooked, pr_url)
message.rebake!(invalidate_oneboxes: true, priority: :low, skip_notifications: true)
end
end
def has_github_pr_onebox?(cooked, pr_url)
# quick & dirty check to avoid doing unnecessary rebakes
cooked.present? && cooked.include?("githubpullrequest") && cooked.include?(pr_url)
.where("cooked LIKE ?", "%githubpullrequest%#{url}%")
.find_each { |message| message.rebake!(priority: :low, skip_notifications: true) }
end
end
end