workbox icon indicating copy to clipboard operation
workbox copied to clipboard

workbox-background-sync/Queue replayRequests change order of request`s

Open TheForsakenSpirit opened this issue 4 years ago • 2 comments

Library Affected: workbox-background-sync

Browser & Platform: Caught on a Mobile Chrome, but can thrown on any.

Issue or Feature Request Description: Queue.replayRequests operation don't block queue storage for adding new request. That can throw switch place of first two request.

Screenshots:queue before inProcess queue_end

For replying issue need in time that replayRequests executed push new request. (In my case thrown by 2 inline request).

Code of my service worker:

import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching';
import { registerRoute, NavigationRoute } from 'workbox-routing';
import { skipWaiting, clientsClaim } from 'workbox-core';
import { CacheFirst } from 'workbox-strategies';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { ExpirationPlugin } from 'workbox-expiration';
import { IgnoreURLParameterPlugin } from './workbox-plugins';
import { Queue } from 'workbox-background-sync';
import * as Messenger from '../src/redux/reducers/util/Messenger';

declare const self: Window & ServiceWorkerGlobalScope & WorkerGlobalScope;

skipWaiting();
clientsClaim();

precacheAndRoute(self.__WB_MANIFEST);

registerRoute(
  ({ url }) => url.origin.includes('s3.amazonaws.com') && !url.pathname.includes('.pdf'),
  new CacheFirst({
    cacheName: 'image-cache',
    plugins: [
      new CacheableResponsePlugin({
        statuses: [200],
      }),
      new IgnoreURLParameterPlugin(),
      new ExpirationPlugin({
        maxEntries: 2000,
        maxAgeSeconds: 3 * 24 * 60 * 60,
      }),
    ],
  }),
  'GET'
);

const handler = createHandlerBoundToURL('/index.html');
const navigationRoute = new NavigationRoute(handler);
registerRoute(navigationRoute);

const queue = new Queue('requestsQueue', {
  maxRetentionTime: 3 * 24 * 60,
  onSync: async (event): Promise<void> => {
    try {
      await event.queue.replayRequests();
    } finally {
      Messenger.sendMessage<number>('requests_queue_length', (await event.queue.getAll()).length);
    }
  },
});

async function sendRequestsQueueLength(): Promise<void> {
  Messenger.sendMessage<number>('requests_queue_length', (await queue.getAll()).length);
}

const replayRequestsQueue = async (): Promise<void> => {
  try {
    await queue.replayRequests();
  } finally {
    await sendRequestsQueueLength();
  }
};

Messenger.createMessageListener<null>('replay_requests_queue', () => {
  replayRequestsQueue();
});

const processRequest = async (request: Request): Promise<Response> => {
  const isQueueEmpty = (await queue.getAll()).length === 0;

  if (isQueueEmpty) {
    try {
      return await fetch(request.clone());
    } catch {} // eslint-disable-line no-empty
  }

  await queue.pushRequest({ request });
  replayRequestsQueue();
  return new Response(null, { status: 200 });
};

self.addEventListener('online', () => {
  replayRequestsQueue();
});

self.addEventListener('fetch', (event: FetchEvent) => {
  if (
    !event.request.url.includes('yembo.ai') ||
    !['POST', 'PUT', 'DELETE'].includes(event.request.method) ||
    event.request.url.endsWith('/login')
  ) {
    return;
  }

  event.respondWith(processRequest(event.request));
});

TheForsakenSpirit avatar Sep 30 '20 11:09 TheForsakenSpirit

Short dive in Queue code. I am create indicator in my code for running replayRequest function and this help avoid dangerous behavior. But question is steel open. Why only sync event check that sync is in Progress? But not a replayRequest function? @jeffposnick Can I create PR with this check?

TheForsakenSpirit avatar Oct 08 '20 08:10 TheForsakenSpirit

@jeffposnick can you share details for how to check with help of workbox that PWA app on android/IOS phone help to check app is running in background and keep calling notifications to fetch?

shinde-prasad avatar Jan 15 '24 01:01 shinde-prasad