Skip to content

Parallelized mention notifications#1627

Merged
rmgpinto merged 1 commit intomainfrom
parallelize-mention-notifications
Mar 4, 2026
Merged

Parallelized mention notifications#1627
rmgpinto merged 1 commit intomainfrom
parallelize-mention-notifications

Conversation

@rmgpinto
Copy link
Collaborator

@rmgpinto rmgpinto commented Mar 2, 2026

@coderabbitai
Copy link

coderabbitai bot commented Mar 2, 2026

Walkthrough

The change modifies the handlePostCreatedEvent function in the notification event service to parallelize mention notification creation. A sequential for-loop that iteratively created mention notifications for each mention is replaced with Promise.all over a mapped array of the same creation calls. The functional behavior of creating notifications for all mentions is preserved, but execution now occurs concurrently rather than sequentially.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: parallelizing mention notifications in the handlePostCreatedEvent function.
Description check ✅ Passed The description references a Linear issue (BER-3241) which is related to the change, though minimal detail is provided.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch parallelize-mention-notifications

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/notification/notification-event.service.ts`:
- Around line 98-105: The current parallel writes over mentions call
this.notificationService.createMentionNotification(post, mention.id) which uses
a raw insert and can create duplicate notifications on retries; update
createMentionNotification to use the same idempotency pattern used for
likes/follows by applying an .onConflict().ignore() (or equivalent conflict
resolution) to the insert into the notifications table (or add a DB unique
constraint on (user_id, account_id, post_id, event_type) and then use
onConflict().ignore()) so concurrent/retried inserts do not produce duplicates.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4e9d547 and 815db03.

📒 Files selected for processing (1)
  • src/notification/notification-event.service.ts

Comment on lines +98 to +105
await Promise.all(
mentions.map((mention) =>
this.notificationService.createMentionNotification(
post,
mention.id,
),
),
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# 1) Find the createMentionNotification implementation
rg -n "createMentionNotification" --type=ts -A 10

Repository: TryGhost/ActivityPub

Length of output: 9025


🏁 Script executed:

# 2) Check the NotificationService implementation for idempotency handling
rg -n "class NotificationService" --type=ts -A 20

Repository: TryGhost/ActivityPub

Length of output: 1650


🏁 Script executed:

# 3) Search for database migrations and schema constraints on notifications
fd -e "migration" -o -e "sql" | head -20

Repository: TryGhost/ActivityPub

Length of output: 180


🏁 Script executed:

# 4) Look for any uniqueness constraints or upsert logic in notification creation
rg -n "unique|constraint|upsert" --type=ts --type=sql | grep -i notif

Repository: TryGhost/ActivityPub

Length of output: 46


🏁 Script executed:

# 5) Check if there are any comments indicating placeholder/dummy status
rg -n "placeholder|dummy|TODO|FIXME|draft" --type=ts src/notification/ | head -20

Repository: TryGhost/ActivityPub

Length of output: 46


🏁 Script executed:

# Get the full implementation of createMentionNotification
sed -n '440,500p' src/notification/notification.service.ts

Repository: TryGhost/ActivityPub

Length of output: 1915


🏁 Script executed:

# Search for database write operations (insert, create, save) in the notification service
rg -n "\.insert\(|\.create\(|\.save\(" src/notification/notification.service.ts -A 5

Repository: TryGhost/ActivityPub

Length of output: 1245


🏁 Script executed:

# Check the notifications table schema in migrations
find . -type f -name "*migration*" | xargs grep -l "notifications" 2>/dev/null | head -5

Repository: TryGhost/ActivityPub

Length of output: 46


🏁 Script executed:

# Look for any database schema definitions for notifications table
rg -n "createTable.*notifications|table.*notifications" --type=ts --type=js -A 15

Repository: TryGhost/ActivityPub

Length of output: 46


🏁 Script executed:

# Check for any idempotency or upsert patterns in notification creation
rg -n "onConflict|onDuplicate|upsert|returning" src/notification/ --type=ts

Repository: TryGhost/ActivityPub

Length of output: 46


🏁 Script executed:

# Check if there's a unique constraint or index on the notifications table
rg -n "notifications" -A 30 --type=ts | grep -E "(unique|constraint|index|primary)" | head -20

Repository: TryGhost/ActivityPub

Length of output: 177


🏁 Script executed:

# Look for the schema/migration files specifically
find . -type f \( -name "*.ts" -o -name "*.js" -o -name "*.sql" \) | xargs grep -l "notifications" | grep -i migrat

Repository: TryGhost/ActivityPub

Length of output: 842


🏁 Script executed:

# Check knex schema builder usage for notifications table
rg -n "notifications" --type=ts -B 5 -A 20 | grep -E "(createTable|table|unique|primary|index)" | head -30

Repository: TryGhost/ActivityPub

Length of output: 838


🏁 Script executed:

# Read the initial notifications table schema
cat migrate/migrations/000026_add-notifications-table.up.sql

Repository: TryGhost/ActivityPub

Length of output: 722


🏁 Script executed:

# Read the down migration for completeness
cat migrate/migrations/000026_add-notifications-table.down.sql

Repository: TryGhost/ActivityPub

Length of output: 99


🏁 Script executed:

# Check the index migration
cat migrate/migrations/000058_add-index-on-notifications-table.up.sql

Repository: TryGhost/ActivityPub

Length of output: 145


🏁 Script executed:

# Check if there are any other places where mention notifications are created
rg -n "createMentionNotification|notifications.*insert" src/notification/ --type=ts | head -20

Repository: TryGhost/ActivityPub

Length of output: 1842


🏁 Script executed:

# Verify the current behavior by checking tests that might reveal idempotency expectations
rg -n "createMentionNotification" src/notification/notification.service.integration.test.ts -B 5 -A 15

Repository: TryGhost/ActivityPub

Length of output: 3363


🏁 Script executed:

# Check if there's any test that calls createMentionNotification twice with the same params
rg -n "createMentionNotification.*createMentionNotification" src/notification/notification.service.integration.test.ts -B 5 -A 10

Repository: TryGhost/ActivityPub

Length of output: 46


🏁 Script executed:

# Look for any idempotency patterns (UPSERT, INSERT...ON DUPLICATE, etc.) elsewhere in the codebase
rg -n "INSERT.*ON|onConflict|merge|upsert" --type=ts --type=sql src/ | head -15

Repository: TryGhost/ActivityPub

Length of output: 1042


🏁 Script executed:

# Check if there's a test that calls createMentionNotification twice with same params to verify duplicate behavior
rg -n "createMentionNotification" src/notification/notification.service.integration.test.ts -B 10 -A 5 | grep -E "(createMentionNotification|expect.*length|it\()" | head -40

Repository: TryGhost/ActivityPub

Length of output: 395


🏁 Script executed:

# Examine the notification-event-service to see if there's retry logic at a higher level
rg -n "retry|Retry|attempt|Attempt|catch|error" src/notification/notification-event.service.ts -B 3 -A 3

Repository: TryGhost/ActivityPub

Length of output: 46


Parallel mention writes without idempotency protection create duplicate notification risk

The Promise.all on line 98 will reject on first failure, but concurrently started writes may succeed, causing partial writes. Without idempotency or a database uniqueness constraint on mention notifications, retrying will create duplicates.

The notifications table lacks a unique constraint on (user_id, account_id, post_id, event_type), and createMentionNotification uses a raw .insert() with no conflict handling. Apply the .onConflict().ignore() pattern (used elsewhere in the codebase for likes and follows) to prevent duplicates on retry.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/notification/notification-event.service.ts` around lines 98 - 105, The
current parallel writes over mentions call
this.notificationService.createMentionNotification(post, mention.id) which uses
a raw insert and can create duplicate notifications on retries; update
createMentionNotification to use the same idempotency pattern used for
likes/follows by applying an .onConflict().ignore() (or equivalent conflict
resolution) to the insert into the notifications table (or add a DB unique
constraint on (user_id, account_id, post_id, event_type) and then use
onConflict().ignore()) so concurrent/retried inserts do not produce duplicates.

@rmgpinto rmgpinto merged commit ea0dc77 into main Mar 4, 2026
12 checks passed
@rmgpinto rmgpinto deleted the parallelize-mention-notifications branch March 4, 2026 14:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant