Mark as seen (queued to avoid 429 rate-limiting)

This commit is contained in:
pa
2026-02-24 20:25:46 +09:00
committed by Natsumi
parent 033b53535e
commit abc82e6988
2 changed files with 72 additions and 29 deletions

View File

@@ -10,6 +10,7 @@ import {
checkCanInvite,
displayLocation,
escapeTag,
executeWithBackoff,
extractFileId,
extractFileVersion,
getUserMemo,
@@ -403,6 +404,71 @@ export const useNotificationStore = defineStore('Notification', () => {
database.seenNotificationV2(notificationId);
}
const seeQueue = [];
const seenIds = new Set();
let seeProcessing = false;
const SEE_CONCURRENCY = 5;
async function processSeeQueue() {
if (seeProcessing) return;
seeProcessing = true;
const worker = async () => {
let item;
while ((item = seeQueue.shift())) {
const { id, version } = item;
try {
await executeWithBackoff(
async () => {
if (version >= 2) {
const args =
await notificationRequest.seeNotificationV2(
{ notificationId: id }
);
handleNotificationV2Update({
params: { notificationId: id },
json: { ...args.json, seen: true }
});
} else {
await notificationRequest.seeNotification({
notificationId: id
});
handleNotificationSee(id);
}
},
{
maxRetries: 3,
baseDelay: 1000,
shouldRetry: (err) =>
err?.status === 429 ||
(err?.message || '').includes('429')
}
);
} catch (err) {
console.warn('Failed to mark notification as seen:', id);
if (version >= 2) {
handleNotificationV2Hide(id);
}
}
}
};
await Promise.all(
Array.from({ length: SEE_CONCURRENCY }, () => worker())
);
seeProcessing = false;
}
/**
* Queue a notification to be marked as seen.
* @param {string} notificationId
* @param {number} [version=1]
*/
function queueMarkAsSeen(notificationId, version = 1) {
if (seenIds.has(notificationId)) return;
seenIds.add(notificationId);
seeQueue.push({ id: notificationId, version });
processSeeQueue();
}
function handleNotificationAccept(args) {
let ref;
const array = notificationTable.value.data;
@@ -2754,6 +2820,7 @@ export const useNotificationStore = defineStore('Notification', () => {
hasUnseenNotifications,
getNotificationCategory,
isNotificationExpired,
openNotificationLink
openNotificationLink,
queueMarkAsSeen
};
});

View File

@@ -249,7 +249,6 @@
import { Badge } from '@/components/ui/badge';
import { Separator } from '@/components/ui/separator';
import { TooltipWrapper } from '@/components/ui/tooltip';
import { notificationRequest } from '@/api';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
@@ -273,7 +272,7 @@
const notificationStore = useNotificationStore();
const { lastLocation } = storeToRefs(useLocationStore());
const { isGameRunning } = storeToRefs(useGameStore());
const { openNotificationLink, isNotificationExpired, handleNotificationV2Hide } = useNotificationStore();
const { openNotificationLink, isNotificationExpired } = useNotificationStore();
const senderName = computed(() => {
const n = props.notification;
@@ -479,34 +478,11 @@
}
onBeforeUnmount(() => {
// Mark as seen
// Mark as seen (queued to avoid 429 rate-limiting)
if (isNotificationExpired(props.notification) || isSeen.value) {
return;
}
const params = { notificationId: props.notification.id };
if (!props.notification.version || props.notification.version < 2) {
notificationRequest.seeNotification({ notificationId: props.notification.id }).then((args) => {
console.log('Marked notification-v1 as seen:', args.json);
notificationStore.handleNotificationSee(props.notification.id);
});
return;
}
notificationRequest
.seeNotificationV2(params)
.then((args) => {
console.log('Marked notification-v2 as seen:', args.json);
const newArgs = {
params,
json: {
...args.json,
seen: true
}
};
notificationStore.handleNotificationV2Update(newArgs);
})
.catch((err) => {
console.error('Failed to mark notification-v2 as seen:', err);
handleNotificationV2Hide(props.notification.id);
});
const version = props.notification.version || 1;
notificationStore.queueMarkAsSeen(props.notification.id, version);
});
</script>