8000 Short Polling · Issue #449 · unjs/ofetch · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Short Polling #449
Open
Open
@tjx666

Description

@tjx666

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0