mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-10-09 00:00:12 +09:00
Delete a room's messages in a job, one transaction each
Room#destroy destroyed every message inside the room's own transaction, which holds SQLite's write lock until the last one: on a room with many messages, every other write in the app waited and failed. The request now takes the room away from its members and leaves the rest to Room::DestroyJob, which destroys the messages one at a time, each in its own short transaction, and then the room. An open room is closed in the request, so that someone who joins the account before the job ends isn't given it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bj8KnxpTf9sj2Ysa8aLAVa
This commit is contained in:
@@ -12,7 +12,7 @@ class RoomsController < ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
@room.destroy
|
||||
@room.destroy_later
|
||||
|
||||
broadcast_remove_room
|
||||
redirect_to root_url
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
class Room::DestroyJob < ApplicationJob
|
||||
discard_on ActiveJob::DeserializationError
|
||||
|
||||
def perform(room)
|
||||
room.destroy_one_message_at_a_time
|
||||
end
|
||||
end
|
||||
@@ -45,6 +45,27 @@ class Room < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
# Takes the room away from its members at once, and leaves its messages to Room::DestroyJob. Destroying them in
|
||||
# the room's own transaction held the database's write lock, and stopped every other write, until the last one.
|
||||
# An open room is closed first, so that no one who joins the account before the job runs is let in.
|
||||
def destroy_later
|
||||
room = open? ? becomes!(Rooms::Closed) : self
|
||||
|
||||
transaction do
|
||||
room.save!
|
||||
room.memberships.delete_all
|
||||
end
|
||||
|
||||
Room::DestroyJob.perform_later(room)
|
||||
end
|
||||
|
||||
# Each message is destroyed in its own transaction, so other writes get through in between. Any message posted
|
||||
# meanwhile goes with the room.
|
||||
def destroy_one_message_at_a_time
|
||||
messages.find_each(&:destroy)
|
||||
destroy
|
||||
end
|
||||
|
||||
def receive(message)
|
||||
unread_memberships(message)
|
||||
push_later(message)
|
||||
|
||||
Reference in New Issue
Block a user