fix: avoid hidden N+1 in workflow comment participants

This commit is contained in:
hjlarry 2026-04-12 20:39:21 +08:00
parent cadc021bfa
commit cf74c5c8db
2 changed files with 43 additions and 14 deletions

View File

@ -101,23 +101,31 @@ class WorkflowComment(Base):
@property
def participants(self):
"""Get all participants (creator + repliers + mentioned users)."""
participant_ids = set()
participant_ids: set[str] = set()
participants: list[Account] = []
# Add comment creator
participant_ids.add(self.created_by)
# Use account properties to reuse preloaded caches and avoid hidden N+1.
if self.created_by not in participant_ids:
participant_ids.add(self.created_by)
created_by_account = self.created_by_account
if created_by_account:
participants.append(created_by_account)
# Add reply creators
participant_ids.update(reply.created_by for reply in self.replies)
for reply in self.replies:
if reply.created_by in participant_ids:
continue
participant_ids.add(reply.created_by)
reply_account = reply.created_by_account
if reply_account:
participants.append(reply_account)
# Add mentioned users
participant_ids.update(mention.mentioned_user_id for mention in self.mentions)
# Get account objects
participants = []
for user_id in participant_ids:
account = db.session.get(Account, user_id)
if account:
participants.append(account)
for mention in self.mentions:
if mention.mentioned_user_id in participant_ids:
continue
participant_ids.add(mention.mentioned_user_id)
mentioned_account = mention.mentioned_user_account
if mentioned_account:
participants.append(mentioned_account)
return participants

View File

@ -60,6 +60,27 @@ def test_workflow_comment_counts_and_participants() -> None:
assert get_mock.call_count == 4
def test_workflow_comment_participants_use_cached_accounts() -> None:
reply = WorkflowCommentReply(comment_id="comment-1", content="reply-1", created_by="user-2")
mention = WorkflowCommentMention(comment_id="comment-1", mentioned_user_id="user-3")
comment = WorkflowComment(created_by="user-1", resolved_by=None, content="hello", position_x=1, position_y=2)
comment.replies = [reply]
comment.mentions = [mention]
account_1 = Mock(id="user-1")
account_2 = Mock(id="user-2")
account_3 = Mock(id="user-3")
comment.cache_created_by_account(account_1)
reply.cache_created_by_account(account_2)
mention.cache_mentioned_user_account(account_3)
with patch("models.comment.db.session.get") as get_mock:
participants = comment.participants
assert set(participants) == {account_1, account_2, account_3}
get_mock.assert_not_called()
def test_reply_and_mention_account_properties_and_cache() -> None:
reply = WorkflowCommentReply(comment_id="comment-1", content="reply", created_by="user-1")
mention = WorkflowCommentMention(comment_id="comment-1", mentioned_user_id="user-2")