Cache boosts with their message instead of one by one

Every boost had its own fragment, nested inside the message fragment that
already holds it. With a cold cache, a read and a write per boost plus a
read_multi and a write_multi per message: a room page of 40 messages with
120 boosts takes ~410 ms instead of ~290 ms. Redis runs without persistence
(config/redis.conf), so every page is cold after a restart.

A boost touches its message, so adding or removing one rewrites the message
fragment anyway. The inner fragments only paid off when a message with many
boosts was drawn again, and there they hid a lookup per booster. The boosters
are now loaded with the boosts, one query per message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0142qgjggdJ2KDdGk7RF9Xm9
This commit is contained in:
Marcello CostagliolaandClaude Opus 5.5 committed 2026-10-05 16:40:49 +02:00
1 parent c73ea37e0c
commit c761763c8c
4 files changed
+60 -19

No files matched your search

+26
View File
@@ -27,6 +27,32 @@ class MessagesCachingTest < ActionDispatch::IntegrationTest
end
end
test "boosts are cached inside their message instead of one fragment each" do
with_memory_cache do
cache_keys = []
subscriber = ActiveSupport::Notifications.subscribe(/\Acache_(read|read_multi|write|write_multi)\.active_support\z/) do |*, payload|
cache_keys.concat(payload[:key].is_a?(Hash) ? payload[:key].keys : Array(payload[:key]))
end
get room_messages_url(rooms(:watercooler))
assert_response :success
assert_select "#" + dom_id(boosts(:fourth_by_bender))
assert_select "#" + dom_id(boosts(:thirteenth))
assert_empty cache_keys.grep(%r{messages/boosts/_boost})
boost = messages(:fourth).boosts.create! booster: users(:jason), content: "🎉"
get room_messages_url(rooms(:watercooler))
refreshed = response.body
Rails.cache.clear
get room_messages_url(rooms(:watercooler))
assert_equal refreshed, response.body
assert_select "##{dom_id(messages(:fourth))} ##{dom_id(boost)}", text: /🎉/
ensure
ActiveSupport::Notifications.unsubscribe(subscriber)
end
end
private
def with_memory_cache
old_cache = Rails.cache