We are currently trying to reflect the actual queue contents into the main menu - using a counter representing pending updates (see picture):

To do so, we are using the brand new getAll() method on the Queue object.
Rather than showing this kind of information on a regular basis (typically upon application startup + every x seconds/minutes), we would like to be able to do it in real-time.
For this, we need to listen/observe the queue operations, especially:
Would it be possible to register some queue listeners (or trigger some events) in order to get notified after each successful pushRequest() and popRequest() so that I can respectively increase or decrease my applicative counter ?
IMHO, it's not a huge job...
This was something I considered in the v4 rewrite (see the "open questions" section of first comment in the PR), but ultimately I opted to not have callbacks as we did in v3 because I thought most advanced users of background sync would be writing their own queue replay code (is this not true in your case?).
Here's a code sample from the comment that shows how to do the custom reply yourself by defining an onSync callback:
const queue = new workbox.backgroundSync.Queue('my-queue-name', {
onSync: async (queue) => {
let entry;
while (entry = await this.shiftRequest()) {
try {
await fetch(entry.request);
console.error('Replay successful for request', entry.request);
} catch (error) {
console.error('Replay failed for request', entry.request, error);
// Put the entry back in the queue and re-throw the error:
await this.unshiftRequest(entry);
throw error;
}
}
console.log('Replay complete!');
}
});
Does this meet your needs?
Yes, I have read that post too. I fully understand (and respect) the motivations of this refactoring: the api is now much easier, at least for basic usage.
The main objection I have is that we basically have (only) two options:
queue.replayRequests() )It's a bit a kind of '_all-or-nothing_' choice.
Beside the standard or custom implementations, it would be really great to have a third option: extend/enrich the standard replay skeleton, and focus on extensions.
Of course, this kind of extension is trivial:
const queue = new workbox.backgroundSync.Queue('my-queue-name', {
onSync: async (queue) => {
// Run standard replay
await queue.replayRequests();
// Do custom *POST* processing (eg update my applicative counter)
console.log('Extra feature');
}
});
but it's limited to the POST processing of the WHOLE backlog.
How (without repeating the skeleton) to add custom processing INSIDE the loop for each INDIVIDUAL queue item ?
The only solution is to copy&paste original replayRequests, and then modifying this code:
const queue = new workbox.backgroundSync.Queue('my-queue-name', {
onSync: async (queue) => {
let entry;
while (entry = await this.shiftRequest()) {
try {
await fetch(entry.request);
// Do custom *INNER* processing (eg decrease my applicative counter by one)
console.log('Extra feature for request', entry.request.url);
} catch (error) {
await this.unshiftRequest(entry);
throw error;
}
}
console.log('Replay complete!');
}
});
Yes it works, but it may sometimes be a pity to repeat 10 lines of source code in order to add one single line :-(
In particular, each time I want the use the standard replay logic + one very little additional feature, I always have to repeat the same skeleton (the loop with shiftRequest, the fetch, the unshift in case of error, etc...).
And if you fix a bug in the replayRequests() method - like you recently did by replacing fetch(entry.request) with fetch(entry.request.clone()) - my implementation will not benefit from this fix.
Does this meet your needs?
I'm afraid not. My use case is not fully covered.
I could indeed implement a custom replay logic in order to decrease my applicative counter, upon the 'sync' event, true.
But how do I handle the incrementation of my counter ?
How can I be notified when the bg-sync plugin is putting a new request into the queue ?
My 2 cents
Bernard.
I think @bligny is right, sometimes you just want to hook in without changing the logic itself, for example when adding a counter
Hi @jeffposnick ! How I can send the requests pending to the client?
I have this code:
addEventListener('fetch', (event) => {
if (['POST, PUT, DELETE'].includes(event.request.method)) {
const promiseChain = fetch(
event.request.clone()
).catch(() => queue.pushRequest({request: event.request}));
event.waitUntil(promiseChain);
}
});
It's ok. Then I want to send these requests failed to the client using the getAll method.
Should I use postMessage?
Thanks!
CC: @philipwalton for guidance.
I suggest this updated version: note the queue destrctured from param
onSync: async ({queue}) => {
let entry;
while ((entry = await queue.shiftRequest())) {
try {
await fetch(entry.request);
console.error("Replay successful for request", entry.request);
} catch (error) {
console.error("Replay failed for request", entry.request, error);
// Put the entry back in the queue and re-throw the error:
await queue.unshiftRequest(entry);
throw error;
}
}
console.log("Replay complete!");
}
I suggest this updated version: note the queue destrctured from param
onSync: async ({queue}) => { let entry; while ((entry = await queue.shiftRequest())) { try { await fetch(entry.request); console.error("Replay successful for request", entry.request); } catch (error) { console.error("Replay failed for request", entry.request, error); // Put the entry back in the queue and re-throw the error: await queue.unshiftRequest(entry); throw error; } } console.log("Replay complete!"); }
yep this is what worked for me. the destructure + the use of queue.shiftRequest() rather than this.shiftRequest()
Most helpful comment
Yes, I have read that post too. I fully understand (and respect) the motivations of this refactoring: the api is now much easier, at least for basic usage.
The main objection I have is that we basically have (only) two options:
queue.replayRequests())It's a bit a kind of '_all-or-nothing_' choice.
Beside the standard or custom implementations, it would be really great to have a third option: extend/enrich the standard replay skeleton, and focus on extensions.
Of course, this kind of extension is trivial:
but it's limited to the POST processing of the WHOLE backlog.
How (without repeating the skeleton) to add custom processing INSIDE the loop for each INDIVIDUAL queue item ?
The only solution is to copy&paste original replayRequests, and then modifying this code:
Yes it works, but it may sometimes be a pity to repeat 10 lines of source code in order to add one single line :-(
In particular, each time I want the use the standard replay logic + one very little additional feature, I always have to repeat the same skeleton (the loop with shiftRequest, the fetch, the unshift in case of error, etc...).
And if you fix a bug in the
replayRequests()method - like you recently did by replacingfetch(entry.request)withfetch(entry.request.clone())- my implementation will not benefit from this fix.I'm afraid not. My use case is not fully covered.
I could indeed implement a custom replay logic in order to decrease my applicative counter, upon the 'sync' event, true.
But how do I handle the incrementation of my counter ?
How can I be notified when the bg-sync plugin is putting a new request into the queue ?
My 2 cents
Bernard.