Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Short Polling #449

Open
1 task done
tjx666 opened this issue Oct 2, 2024 · 0 comments
Open
1 task done

Short Polling #449

tjx666 opened this issue Oct 2, 2024 · 0 comments
Labels
enhancement New feature or request

Comments

@tjx666
Copy link

tjx666 commented Oct 2, 2024

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?
@tjx666 tjx666 added the enhancement New feature or request label Oct 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant