fix: serialiseer alle media-sends in één keten + pacing ertussen

Gelijktijdige webhook-requests (afbeeldingen naar verschillende ontvangers)
konden overlappen in de ene chromium-tab. nu loopt élke media-send door een
seriële keten en eindigt met MEDIA_SEND_DELAY_MS, zodat de tab tussen twee
sends rust krijgt. Smoke-test: 3 gelijktijdige sends -> gaps ~delay.
This commit is contained in:
Eddy de Vink 2026-09-26 22:28:52 +02:00
commit 79ff8790b9

View file

@ -19,6 +19,19 @@ async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms)) return new Promise(resolve => setTimeout(resolve, ms))
} }
// Media-send seriële keten: de wwebjs-media-pipeline is EÉN chromium-tab. Zonder
// serialisatie overlappen opeenvolgende media-sends — pagina's van één dienst óf
// afbeeldingen naar verschillende ontvangers bij gelijktijdige webhook-requests.
// Daarom loopt élke media-send door deze ene keten en eindigt elke send met
// MEDIA_SEND_DELAY_MS, zodat de tab tussen twee sends rust krijgt.
let mediaSendChain = Promise.resolve()
function enqueueSend(run) {
const job = mediaSendChain.then(run, run)
mediaSendChain = job.catch(() => {}) // keten levend houden, ook als een send faalt
return job
}
function isRetryableError(error) { function isRetryableError(error) {
if (error.response) { if (error.response) {
const status = error.response.status const status = error.response.status
@ -56,6 +69,10 @@ async function sendTextMessage(chatId, text) {
} }
async function sendImageMessage(chatId, filePath, filename) { async function sendImageMessage(chatId, filePath, filename) {
return enqueueSend(() => sendImageMessageInner(chatId, filePath, filename))
}
async function sendImageMessageInner(chatId, filePath, filename) {
return withRetry(async () => { return withRetry(async () => {
const fileBuffer = fs.readFileSync(filePath) const fileBuffer = fs.readFileSync(filePath)
const base64Data = fileBuffer.toString('base64') const base64Data = fileBuffer.toString('base64')
@ -71,7 +88,7 @@ async function sendImageMessage(chatId, filePath, filename) {
}) })
const messageId = response.data?.message?._data?.id?.id const messageId = response.data?.message?._data?.id?.id
registerSend(messageId, chatId, filename) registerSend(messageId, chatId, filename)
// Pacing na élke media-send: de wwebjs-media-pipeline is EEN chromium-tab. Twee // Pacing ná élke media-send: de wwebjs-media-pipeline is EEN chromium-tab. Twee
// opeenvolgende media-sends (pagina's van één dienst óf afbeeldingen naar // opeenvolgende media-sends (pagina's van één dienst óf afbeeldingen naar
// verschillende ontvangers) mogen niet overlappen — dat veroorzaakt de staged- // verschillende ontvangers) mogen niet overlappen — dat veroorzaakt de staged-
// ghost-race (2e send verliest). Wacht dus altijd MEDIA_SEND_DELAY_MS ná een send. // ghost-race (2e send verliest). Wacht dus altijd MEDIA_SEND_DELAY_MS ná een send.