feat: gamification queue with deduplication and unpublish revoke
- Add migration 0004: partial unique index on user_points (user_id, action, recording_id) for RECORDING_CREATE and RECORDING_FEATURED to prevent earn-on-republish farming - Add revokePoints() to gamification lib; awardPoints() now uses onConflictDoNothing - Add gamificationQueue (BullMQ) with 3-attempt exponential backoff - Add gamification worker handling awardPoints, revokePoints, checkAchievements jobs - Move all inline gamification calls in recordings + comments resolvers to queue - Revoke RECORDING_CREATE points when a recording is unpublished (published → draft) - Register gamification worker at server startup alongside mail worker Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,13 +5,21 @@ import { logger } from "../lib/logger.js";
|
||||
const log = logger.child({ component: "queues" });
|
||||
|
||||
export const mailQueue = new Queue("mail", { connection: redisConnectionOpts });
|
||||
|
||||
mailQueue.on("error", (err) => {
|
||||
log.error({ queue: "mail", err: err.message }, "Queue error");
|
||||
});
|
||||
|
||||
log.info("Mail queue initialized");
|
||||
export const gamificationQueue = new Queue("gamification", {
|
||||
connection: redisConnectionOpts,
|
||||
defaultJobOptions: { attempts: 3, backoff: { type: "exponential", delay: 2000 } },
|
||||
});
|
||||
gamificationQueue.on("error", (err) => {
|
||||
log.error({ queue: "gamification", err: err.message }, "Queue error");
|
||||
});
|
||||
|
||||
log.info("Queues initialized");
|
||||
|
||||
export const queues: Record<string, Queue> = {
|
||||
mail: mailQueue,
|
||||
gamification: gamificationQueue,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user