unjs / unjs/ofetch

Short Polling

Open
#449 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
TypeScript
Stars
5.4k
Forks
195
PR merge metrics
No merged PRs in 30d

Description

Describe the feature

Why

Nowadays, many ai services are provided by http api, the task normally cost long time, http short polling is a simple way to get the result. For example: https://platform.tripo3d.ai/docs/task#polling

Solution

I previous implement it like following:

import EventEmitter from 'events'

import { omit } from 'lodash-es'
import type { Promisable } from 'type-fest'

interface EventData<D extends Record<string, any> = {}> {
  start: void
  response: D
  error: any
  stop: void
}

type Event = keyof EventData

type Options = RequestInit & {
  interval?: number
  pollingTimeout?: number
}

/**
 * Http Short Polling
 */
export class HttpShortPoll<D> extends EventEmitter {
  url: string
  status: 'init' | 'polling' | 'stopped' = 'init'
  _pollingTimer: NodeJS.Timeout | null = null
  _startTimestamp: number | null = null
  options: Options = {
    interval: 1000,
    // 20 minutes
    pollingTimeout: 1000 * 60 * 20,
  }

  constructor(url: string, options?: Options) {
    super()
    this.url = url
    this.options = { ...this.options, ...options }
  }

  on<E extends Event>(event: E, listener: (data: EventData<D>[E]) => Promisable<void>) {
    return super.on(event, listener)
  }

  emit<E extends Event>(event: E, data?: EventData<D>[E]) {
    return super.emit(event, data)
  }

  start() {
    if (this.status !== 'init') {
      return
    }

    this.status = 'polling'
    this.emit('start')
    this._startTimestamp = Date.now()

    this._pollingTimer = setInterval(async () => {
      if (this.status !== 'polling') {
        return
      }

      if (Date.now() - this._startTimestamp > this.options.pollingTimeout) {
        this.stop()
        return
      }

      try {
        const resp = await fetch(this.url, omit(this.options, ['interval', 'pollingTimeout']))
        const json = await resp.json()
        this.emit('response', json as D)
      } catch (error) {
        console.error(error)
        this.emit('error', error)
        return
      }
    }, this.options.interval)
  }

  stop() {
    this.status = 'stopped'

    if (this._pollingTimer) {
      clearInterval(this._pollingTimer)
      this._pollingTimer = null
    }

    this.emit('stop')
  }
}

// for example
const poll = new HttpShortPoll('https://api.example.com/data', {
  interval: 1000,
  pollingTimeout: 10000,
})
poll.on('start', () => {
  console.log('Polling started')
})
poll.on('response', (data) => {
  console.log('Data received:', data)
})
poll.on('error', (error) => {
  console.error('Error:', error)
})
poll.on('stop', () => {
  console.log('Polling stopped')
})
Additional information
  • Would you be willing to help implement this feature?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue provides a proposed TypeScript HttpShortPoll implementation but names no repository files or tests. Start by reading ofetch’s public API and test layout, then determine where polling belongs and verify interval, timeout, response, error, and stop behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.