OverviewFilesCommitsIssuesDocsReleasesPeers

ollama_semantic_function_calling / ollamatools-new / keet / node_modules / autobase / lib / timer.js

126 lines · javascript ref:
const safetyCatch = require('safety-catch')

const MAX_WAIT = 2 * 60 * 1000
const DEFAULT_INTERVAL = 10 * 1000

module.exports = class Timer {
  constructor (handler, interval, opts = {}) {
    this.handler = handler || noop
    this.interval = interval || DEFAULT_INTERVAL
    this.limit = opts.limit || MAX_WAIT

    this._executing = null

    this._limit = random2over1(this.limit)
    this._timer = null
    this._resolve = null
    this._start = 0
    this._stopped = false
    this._asap = false
    this._standalone = new Set()

    this._unref = opts.unref !== false
    this._timerCallback = this._executeBackground.bind(this)
  }

  _executeBackground () {
    this._executing = this._execute()
    this._executing.catch(safetyCatch) // make sure it doesnt crash in the bg
  }

  async _execute () {
    this._asap = false
    await this.handler()
    this._start = 0
    this._executing = null
    this.bump()
  }

  bump () {
    if (this._stopped || this._executing || this._asap) return

    if (!this._start) this._start = Date.now()
    else if (Date.now() - this._start > this._limit) return

    const interval = random2over1(this.interval)

    clearTimeout(this._timer)
    this._timer = setTimeout(this._timerCallback, interval)
    if (this._unref && this._timer.unref) this._timer.unref()
  }

  async trigger () {
    if (this._stopped) return
    if (this._executing) await this._executing
    if (this._stopped) return

    clearTimeout(this._timer)
    this._timer = null

    this._executeBackground()
    await this._executing
  }

  async flush () {
    if (this._executing) await this._executing
  }

  // business-as-usual
  bau () {
    if (!this._asap) return
    this._asap = false
    this.bump()
  }

  asap () {
    if (this._asap) return
    this._asap = true

    const interval = Math.floor(Math.random() * this.interval / 3)
    clearTimeout(this._timer)
    this._timer = setTimeout(this._timerCallback, interval)
    if (this._unref && this._timer.unref) this._timer.unref()
  }

  stop () {
    if (this._timer) clearTimeout(this._timer)
    this._timer = null
    this._start = 0
    this._asap = false
    this._stopped = true

    for (const { timer, resolve } of this._standalone) {
      clearTimeout(timer)
      resolve()
    }

    this._standalone.clear()
  }

  asapStandalone () {
    const interval = Math.floor(Math.random() * this.interval / 3)
    return new Promise((resolve) => {
      const ref = { timer: null, resolve }
      ref.timer = setTimeout(resolveStandalone, interval, ref, this._standalone)
      if (ref.timer.unref) ref.timer.unref()
      this._standalone.add(ref)
    })
  }

  unref () {
    if (this._timer && this._timer.unref) this._timer.unref()
  }
}

function resolveStandalone (ref, set) {
  set.delete(ref)
  ref.resolve()
}

// random value x between n <= x < 2n
function random2over1 (n) {
  return Math.floor(n + Math.random() * n)
}

function noop () {}