Skip to content

Latest commit

 

History

History
283 lines (215 loc) · 10.3 KB

README.md

File metadata and controls

283 lines (215 loc) · 10.3 KB

polling-observer

A new way of running polling function with observer pattern


MIT License

Like PerformanceObserver or any other observer APIs you could find in a browser, but this is for polling. Not only does it run polling with defined parameters but also collect polling metrics for each run until timeout or a defined condition fulfills.

Table of contents

Performance API

This relies on Performance API which is available globally by default. For Node.js users, the API has been implemented and shipped as of Node.js v8.5.0. But it is not one of the global APIs, do the following before using the module:

const { performance } = require('perf_hooks');
global.performance = performance;

Usage

interface DataType {
  status: 'complete' | 'in-progress';
  items: Record<string, any>[];
}

import { PollingObserver } from 'nodemod/dist/polling-observer/index.js';

const obs = new PollingObserver((data/** list, observer */) => {
  const { status, items } = data || {};
  const itemsLen = (items && items.length) || 0;

  /** Stop polling when any of the conditions fulfills */
  return 'complete' === status || itemsLen > 99;
});

/**
 * When polling finishes, it will either fulfill or reject depending on the status:
 * 
 * | Status  | Returns   |
 * | ------- | --------- |
 * | finish  | <value>   |
 * | timeout | <value>   |
 * | error   | <reason>  |
 * 
 * Alternatively, `obs.addEventListener('finish', ...);` works too.
 */
obs.onfinish = (data, records/**, observer */) => {
  const { status, value, reason } = data || {};

  switch (status) {
    case 'error': {
      console.error(`Polling fails due to: `, reason);
      break;
    }
    case 'timeout': {
      console.log(`Polling timeouts after 30 seconds: `, value);
      break;
    }
    case 'finish':
    default: {
      console.log(`Polling finishes: `, value);
    }
  }

  console.log(`Formatted polling records: `, records.map(n => n.toJSON()));
  /**
   * [
   *   {
   *     duration: 100,
   *     entryType: 'polling-measure',
   *     name: 'polling:0',
   *     startTime: 100,
   *   },
   *   ...
   * ]
   */

  obs.disconnect(); /** Disconnect to clean up */
};

obs.observe(
  async () => {
    /** Polling callback - fetch resources */
    const r = await fetch('https://example.com/api?key=123');
    const d = await r.json();

    return d;
  },
  /** Run polling (at least) every 2 seconds and timeout if it exceeds 30 seconds */
  {
    interval: 2e3,
    timeout: 30e3,
  }
);

API Reference

OnfinishFulfilled<T>

interface OnfinishFulfilled<T> {
  status: 'finish' | 'timeout';
  value: T;
}

OnfinishRejected

interface OnfinishRejected {
  status: 'error';
  reason: Error;
}

PollingMeasure

interface PollingMeasure {
  duration: number;
  entryType: 'polling-measure';
  name: string;
  startTime: number;
}
  • duration <number> Duration of the polling takes in milliseconds.
  • entryType <string> Entry type, defaults to polling-measure.
  • name <string> Polling name in the format of polling:<index> where <index> starts from 0 and increments on each polling.
  • startTime <string> Relative timestamp (in milliseconds ) indicates when the polling starts at.

Methods

PollingMeasure.toJSON()
  • <Function> Returns a JSON representation of the polling object's properties.

PollingObserver<T>

Methods

PollingObserver.observe(callback[, options])

The method is used to initiate polling with a polling callback and optional configuration.

  • callback <Function> Callback to be executed in each polling and return the result so that it will be passed as the first argument in conditionCallback.
    • returns: <T | Promise<T>> Return polling result in the type of T or Promise<T> in each polling.
  • options <Object> Optional configuration to run the polling.
    • interval <number> Optional interval in milliseconds. This is the minimum delay before starting the next polling.
    • timeout <number> Optional timeout in milliseconds. Polling ends when it reaches the defined timeout even though the condition has not been met yet. As long as timeout is not a number or it has a value that is less than 1, it indicates an infinite polling. The polling needs to be stopped manually by calling PollingObserver.disconnect() method.
PollingObserver.disconnect()

Once a PollingObserver disconnects, the polling stops and all polling metrics will be cleared. Calling PollingObserver.takeRecords() after the disconnection will always return an empty record.

A onfinish event handler can be used to retrieve polling records after a disconnection but it has to be attached before disconnecting the observer.

PollingObserver.takeRecords()

The method returns a list of PollingMeasure object containing the metrics of each polling.

Event handler

PollingObserver.onfinish

Alternatively, an event handler can be setup to listen for the finish event. See finish.

Event handler for when a polling finishes. When a polling finishes, it can either be fulfilled with a value or rejected with a reason. Any one of which contains a status field to tell the state of the finished polling.

Events

finish

finish event fires when a polling finishes.

const obs = new PollingObserver(/** --snip */);
// --snip

/** Same as using obs.onfinish = ... */
obs.addEventListener('finish', (ev: CustomEvent) => {
  const {
    detail: [
      { status, value/**, reason */ },
      records,
      observer,
    ],
  } = ev;

  // --snip
});

License

MIT License © Rong Sen Ng