fix: 🐛 race condition between workers when creating note

Closes #10345
Discovered here: https://codeberg.org/calckey/calckey/issues/10345#issuecomment-950475
This commit is contained in:
ThatOneCalculator 2023-06-23 17:27:25 -07:00
parent 7640f4d3f8
commit c0f6a53223
No known key found for this signature in database
GPG Key ID: 8703CACD01000000
1 changed files with 34 additions and 20 deletions

View File

@ -465,26 +465,40 @@ export default async (
if (!note.uri) { if (!note.uri) {
// Publish if the post is local // Publish if the post is local
publishNotesStream(note); publishNotesStream(note);
} else if ( } else if (boostedByRelay && data.renote?.uri) {
boostedByRelay && // Use Redis transaction for atomicity
data.renote?.uri && await redisClient.watch(`publishedNote:${data.renote.uri}`);
(await redisClient.exists(`publishedNote:${data.renote.uri}`)) === 0 const exists = await redisClient.exists(
) { `publishedNote:${data.renote.uri}`,
// Publish if the post was boosted by a relay and not yet published. );
publishNotesStream(data.renote); if (exists === 0) {
const key = `publishedNote:${data.renote.uri}`; // Start the transaction
await redisClient.set(key, 1, "EX", 30); redisClient.multi();
} else if ( publishNotesStream(data.renote);
!boostedByRelay && const key = `publishedNote:${data.renote.uri}`;
note.uri && await redisClient.set(key, 1, "EX", 30);
(await redisClient.exists(`publishedNote:${note.uri}`)) === 0 // Execute the transaction
) { redisClient.exec();
// Publish if the post came directly from a remote server, or from a } else {
// relay that doesn't boost the post (e.g, YUKIMOCHI Activity-Relay), // Abort the transaction
// and not yet published. redisClient.unwatch();
const key = `publishedNote:${note.uri}`; }
publishNotesStream(note); } else if (!boostedByRelay && note.uri) {
await redisClient.set(key, 1, "EX", 30); // Use Redis transaction for atomicity
await redisClient.watch(`publishedNote:${note.uri}`);
const exists = await redisClient.exists(`publishedNote:${note.uri}`);
if (exists === 0) {
// Start the transaction
redisClient.multi();
publishNotesStream(note);
const key = `publishedNote:${note.uri}`;
await redisClient.set(key, 1, "EX", 30);
// Execute the transaction
redisClient.exec();
} else {
// Abort the transaction
redisClient.unwatch();
}
} }
} }
if (note.replyId != null) { if (note.replyId != null) {