gallery_server_client_s190js/ws-server/ws-outbox-consumer.js
2026-10-26 11:00:14 +01:00

119 lines
2.3 KiB
JavaScript

'use strict';
const db = require('../db/knex');
const {
broadcastPhotoEvent,
broadcastActivityEvent,
} = require('../ws-server');
const {
ensureServerEventOutbox,
getNextPendingServerEvent,
completeServerEvent,
failServerEvent,
} = require('../db/serverEventOutbox');
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function dispatchEvent(event) {
let payload;
try {
payload = JSON.parse(event.payload);
} catch (err) {
throw new Error(
`Payload JSON non valido per evento ${event.id}: ${err.message}`
);
}
switch (event.channel) {
case 'photo':
await broadcastPhotoEvent(event.user, payload);
return;
case 'activity':
await broadcastActivityEvent(event.user, payload);
return;
default:
throw new Error(
`Canale outbox sconosciuto: ${event.channel}`
);
}
}
function startWsOutboxConsumer(options = {}) {
const pollMs = Math.max(
100,
Number(options.pollMs) || 250
);
let stopping = false;
async function loop() {
await ensureServerEventOutbox(db);
console.log(
`[WsOutboxConsumer] avviato; polling ${pollMs} ms`
);
while (!stopping) {
try {
const event = await getNextPendingServerEvent(db);
if (!event) {
await sleep(pollMs);
continue;
}
try {
await dispatchEvent(event);
await completeServerEvent(db, event.id);
console.log(
`[WsOutboxConsumer] evento ${event.id} inviato ` +
`channel=${event.channel} user=${event.user}`
);
} catch (err) {
await failServerEvent(
db,
event.id,
err.message
);
console.error(
`[WsOutboxConsumer] evento ${event.id} fallito:`,
err.message
);
// Evita un busy-loop continuo su un evento non valido.
await sleep(pollMs);
}
} catch (err) {
console.error(
'[WsOutboxConsumer] errore ciclo:',
err
);
await sleep(pollMs);
}
}
}
loop().catch((err) => {
console.error(
'[WsOutboxConsumer] errore fatale:',
err
);
});
return () => {
stopping = true;
};
}
module.exports = {
startWsOutboxConsumer,
};