-
Notifications
You must be signed in to change notification settings - Fork 5.1k
fix: normalize remoteJid in message updates and handle race condition in contact cache #2321
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: normalize remoteJid in message updates and handle race condition in contact cache #2321
Conversation
… in contact cache
Reviewer's GuideNormalizes Baileys message update JIDs in-place, adds a retry mechanism and JID synchronization when loading original messages for updates, and hardens the WhatsApp contact cache against Prisma unique-constraint race conditions by catching P2002 and updating instead of failing. Sequence diagram for Baileys messages.update handling with JID normalization and retrysequenceDiagram
participant BaileysSocket
participant BaileysStartupService
participant PrismaRepository
participant DelayUtil
BaileysSocket->>BaileysStartupService: messages.update(args)
loop for each update in args
BaileysStartupService->>BaileysStartupService: Normalize key.remoteJid
BaileysStartupService->>BaileysStartupService: Normalize key.participant
BaileysStartupService->>BaileysStartupService: Check settings.groupsIgnore and group JIDs
alt update references original message
BaileysStartupService->>BaileysStartupService: Determine searchId
loop up to maxRetries (3)
BaileysStartupService->>PrismaRepository: $queryRaw SELECT Message WHERE key->>id = searchId LIMIT 1
PrismaRepository-->>BaileysStartupService: Message or null
alt message found
BaileysStartupService->>BaileysStartupService: Assign findMessage
BaileysStartupService->>BaileysStartupService: break loop
else message not found
BaileysStartupService->>DelayUtil: delay(2000ms)
DelayUtil-->>BaileysStartupService: resume
end
end
alt findMessage missing
BaileysStartupService->>BaileysStartupService: logger.warn Original message not found
BaileysStartupService-->>BaileysStartupService: continue to next update
else findMessage present
alt stored key.remoteJid differs from incoming key.remoteJid
BaileysStartupService->>BaileysStartupService: logger.verbose Updating key.remoteJid
BaileysStartupService->>BaileysStartupService: key.remoteJid = findMessage.key.remoteJid
end
BaileysStartupService->>BaileysStartupService: message.messageId = findMessage.id
end
else no original message reference
BaileysStartupService->>BaileysStartupService: Process update without lookup
end
end
Sequence diagram for saveOnWhatsappCache with P2002 race condition handlingsequenceDiagram
participant Caller
participant saveOnWhatsappCache
participant PrismaRepository
Caller->>saveOnWhatsappCache: saveOnWhatsappCache(data[])
loop for each dataPayload in data[]
saveOnWhatsappCache->>PrismaRepository: isOnWhatsapp.findUnique(remoteJid)
PrismaRepository-->>saveOnWhatsappCache: existingRecord or null
alt existingRecord exists
saveOnWhatsappCache->>PrismaRepository: isOnWhatsapp.update(where remoteJid, dataPayload)
PrismaRepository-->>saveOnWhatsappCache: updatedRecord
else record does not exist
saveOnWhatsappCache->>saveOnWhatsappCache: logger.verbose creating record
saveOnWhatsappCache->>PrismaRepository: isOnWhatsapp.create(dataPayload)
alt create succeeds
PrismaRepository-->>saveOnWhatsappCache: createdRecord
else create throws error
PrismaRepository-->>saveOnWhatsappCache: error
alt error.code is P2002 and error.meta.target includes remoteJid
saveOnWhatsappCache->>saveOnWhatsappCache: logger.verbose race condition detected
saveOnWhatsappCache->>PrismaRepository: isOnWhatsapp.update(where remoteJid, dataPayload)
PrismaRepository-->>saveOnWhatsappCache: updatedRecord
else other error
saveOnWhatsappCache-->>Caller: throw error
end
end
end
end
saveOnWhatsappCache-->>Caller: completion
Flow diagram for message lookup retry loop in messages.updateflowchart TD
A[Start message update handling] --> B[Normalize key.remoteJid and key.participant]
B --> C[Determine searchId]
C --> D[Set retries = 0, maxRetries = 3]
D --> E{retries < maxRetries}
E -- No --> F[Log original message not found]
F --> G[Skip this update]
G --> H[Next update or end]
E -- Yes --> I[Query Message by instanceId and key id]
I --> J{Message found}
J -- Yes --> K[Set findMessage]
K --> L{findMessage.key.remoteJid differs from key.remoteJid}
L -- Yes --> M[Update key.remoteJid from stored message]
M --> N[Set message.messageId = findMessage.id]
L -- No --> N[Set message.messageId = findMessage.id]
N --> H
J -- No --> O[Increment retries]
O --> P{retries < maxRetries}
P -- Yes --> Q[delay 2000ms]
Q --> E
P -- No --> F
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes - here's some feedback:
- The retry loop for fetching the original message can add up to ~6 seconds of blocking per update within the
for awaithandler; consider making the retry delay and count configurable or shortening the delay to avoid increasing end-to-end latency under load. - When updating
key.remoteJidfrom the stored message, it may be worth adding a brief comment explaining why it is safe to mutate the incoming key object and how this interacts with any downstream logic that might assume the normalized (device-suffix-stripped) form. - In
saveOnWhatsappCache, instead of checkingerror.code === 'P2002'onany, consider narrowing the type (e.g., toPrismaClientKnownRequestError) so the error handling is more robust to unrelated errors with acodeproperty.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The retry loop for fetching the original message can add up to ~6 seconds of blocking per update within the `for await` handler; consider making the retry delay and count configurable or shortening the delay to avoid increasing end-to-end latency under load.
- When updating `key.remoteJid` from the stored message, it may be worth adding a brief comment explaining why it is safe to mutate the incoming key object and how this interacts with any downstream logic that might assume the normalized (device-suffix-stripped) form.
- In `saveOnWhatsappCache`, instead of checking `error.code === 'P2002'` on `any`, consider narrowing the type (e.g., to `PrismaClientKnownRequestError`) so the error handling is more robust to unrelated errors with a `code` property.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
📋 Description
This PR addresses two critical issues related to data consistency and race conditions in
the WhatsApp integration (Baileys) and contact caching mechanism:
Original Message Not Found (Fix):
remoteJidandparticipantin themessages.updatehandler to remove device suffixes (e.g.,:42@s.whatsapp.net->@s.whatsapp.net). This ensures that keys used for lookups matchthe stored format.
key.remoteJidwith the value stored in the database if the message is found. This resolves mismatches
where an update might come in with a LID while the stored message uses a phone number JID
(or vice versa), ensuring the correct identifier is used for subsequent logic.
the original message for an update. This handles race conditions where the
messages.updateevent arrives before the initialmessages.upserthas finishedcommitting the message to the database.
Unique Constraint Failed in Cache (Fix):
prismaRepository.isOnWhatsapp.createcall in a
try-catchblock specifically catchingP2002(Unique Constraint Violation)errors on
remoteJid.the record between the check and the insert), the code now gracefully falls back to
updating the existing record instead of crashing.
🔗 Related Issue
Closes # (Add issue number if applicable)
🧪 Type of Change
work as expected)
🧪 Testing
remoteJidno longer crash theprocess.
📸 Screenshots (if applicable)
✅ Checklist
📝 Additional Notes
The race condition in
saveOnWhatsappCachewas causing intermittentP2002errors inlogs, which are now handled gracefully. The
messages.updatefixes ensure that readreceipts and other status updates are correctly applied even when network events arrive
out of order or with slightly different JID formats.
Summary by Sourcery
Normalize WhatsApp message identifiers in update handling and add safeguards against race conditions in message lookup and contact cache writes.
Bug Fixes: