oasis.js icon indicating copy to clipboard operation
oasis.js copied to clipboard

Can polling get stuck if an event id is skipped?

Open lukaw3d opened this issue 5 years ago • 2 comments

When fixing IDLE_TIMELAPSE in https://github.com/oasislabs/oasis.js/pull/342/commits/1de0463e3115159a871c3a8143a7ed53b8e67fa8 I noticed that polling for event 1 and 3 would still never trigger IDLE_TIMELAPSE.

  fit('IDLE_TIMELAPSE... only works if empty responses, but they wouldnt be empty if event skipped', async () => {
    const originalIdleTimeout = PollingService['IDLE_TIMELAPSE'];
    const POLLING_INTERVAL = 100;
    PollingService['IDLE_TIMELAPSE'] = 200;
    PollingService['SERVICES'] = new Map();

    class LogSession implements Http {
      public async request(method: string, api: string, body: any): Promise<any> {
        if (body.offset === 1) {
          const response = {
            offset: 1,
            events: [successEvent(1), successEvent(3)],
          };
          console.log('Polling', body, ' => responded', response.events.map(({id}) => id));
          return response;
        }
        if (body.offset === 2) {
          const response = {
            offset: 2,
            events: [successEvent(3)],
          };
          console.log('Polling', body, ' => responded', response.events.map(({id}) => id));
          return response;
        }
        throw new Error('unhandled test case');
      }
    }
    const session = new LogSession();
    const service = PollingService.instance({
      url: 'test',
      session: session,
      interval: 100,
    });

    const a = service.response(1);
    console.log('Poll for id 1');
    const b = service.response(3);
    console.log('Poll for id 3');

    await expect(a).resolves.toEqual(successEvent(1));
    await expect(b).resolves.toEqual(successEvent(3));
    await new Promise(resolve => setTimeout(resolve, POLLING_INTERVAL + PollingService['IDLE_TIMELAPSE'] + 1));
    console.error(`Expected IDLE_TIMELAPSE=${PollingService['IDLE_TIMELAPSE']} to stop the polling by now?`);
    await new Promise(resolve => setTimeout(resolve, PollingService['IDLE_TIMELAPSE'] * 5));
    console.error('Forever');


    service.stop();
    PollingService['IDLE_TIMELAPSE'] = originalIdleTimeout;
  });

Output

Poll for id 1
Poll for id 3
Polling { offset: 1, discardPrevious: true, id: undefined }  => responded [ 1, 3 ]

Polling { offset: 2, discardPrevious: true, id: undefined }  => responded [ 3 ]
Polling { offset: 2, discardPrevious: true, id: undefined }  => responded [ 3 ]
Polling { offset: 2, discardPrevious: true, id: undefined }  => responded [ 3 ]
Expected IDLE_TIMELAPSE=200 to stop the polling by now?

Polling { offset: 2, discardPrevious: true, id: undefined }  => responded [ 3 ]
Polling { offset: 2, discardPrevious: true, id: undefined }  => responded [ 3 ]
Polling { offset: 2, discardPrevious: true, id: undefined }  => responded [ 3 ]
Polling { offset: 2, discardPrevious: true, id: undefined }  => responded [ 3 ]
Polling { offset: 2, discardPrevious: true, id: undefined }  => responded [ 3 ]
Polling { offset: 2, discardPrevious: true, id: undefined }  => responded [ 3 ]
Polling { offset: 2, discardPrevious: true, id: undefined }  => responded [ 3 ]
Forever

lukaw3d avatar May 06 '20 21:05 lukaw3d

Update after https://github.com/oasislabs/oasis.js/pull/350: IDLE_TIMELAPSE was removed, so if an event id is skipped (Poll for id 1 and 3), it will definitely poll forever.

lukaw3d avatar Jun 18 '20 21:06 lukaw3d

Isn't it possible for the server to respond with [1, 3] first, and then [2] later? The events don't need to happen in the order we subscribed to them. In which case, it's fine to keep waiting for 2 forever.

But IIUC this was indeed a bug before, while we still had IDLE_TIMELAPSE. Nicely spotted, and I :heart: the unit test.

mitjat avatar Jun 19 '20 08:06 mitjat