<commit_before>import Promise from 'bluebird'
import createDebug from 'debug'

const debug = createDebug('miniplug:backoff')

/**
 * Create a linear incremental backoff function. Returns a function that wraps
 * a Promise-returning function.
 *
 * **Usage**
 *
 *   const func = () => Promise.resolve('done')
 *   const backoff = createBackoff({ increment: 200, max: 2200 })
 *   const throttled = backoff(func)
 *   throttled().then(console.log) // Resolves immediately
 *   throttled().then(console.log) // Resolves after 200 ms
 */
export default function createBackoff ({ increment, max }) {
  let queuedCalls = 0
  let currentDelay = 0
  let lastCall = Promise.resolve()

  function queueCall () {
    queuedCalls += 1
    // Keep increasing the delay as more calls are queued.
    currentDelay = Math.min(currentDelay + increment, max)
    debug('queued', queuedCalls, currentDelay)
  }
  function unqueueCall () {
    queuedCalls -= 1
    // If our queue is empty, reset the delay.
    if (queuedCalls === 0) {
      currentDelay = 0
    }
    debug('unqueued', queuedCalls, currentDelay)
  }

  return (fn) => function (...args) {
    queueCall()

    debug('calling args', args.length)

    // `result` will resolve with the result of the function call.
    const result = lastCall.then(() => fn(...args))

    // `lastCall` will resolve after the backoff duration is over.
    lastCall = result.return(null) // Ignore return value of previous call.
      .delay(currentDelay)
      .tap(unqueueCall)

    return result
  }
}<commit_msg>Fix subsequent HTTP/chat requests after one fails<commit_after>import Promise from 'bluebird'
import createDebug from 'debug'

const debug = createDebug('miniplug:backoff')

/**
 * Create a linear incremental backoff function. Returns a function that wraps
 * a Promise-returning function.
 *
 * **Usage**
 *
 *   const func = () => Promise.resolve('done')
 *   const backoff = createBackoff({ increment: 200, max: 2200 })
 *   const throttled = backoff(func)
 *   throttled().then(console.log) // Resolves immediately
 *   throttled().then(console.log) // Resolves after 200 ms
 */
export default function createBackoff ({ increment, max }) {
  let queuedCalls = 0
  let currentDelay = 0
  let lastCall = Promise.resolve()

  function queueCall () {
    queuedCalls += 1
    // Keep increasing the delay as more calls are queued.
    currentDelay = Math.min(currentDelay + increment, max)
    debug('queued', queuedCalls, currentDelay)
  }
  function unqueueCall () {
    queuedCalls -= 1
    // If our queue is empty, reset the delay.
    if (queuedCalls === 0) {
      currentDelay = 0
    }
    debug('unqueued', queuedCalls, currentDelay)
  }

  return (fn) => function (...args) {
    queueCall()

    debug('calling args', args.length)

    // `result` will resolve with the result of the function call.
    const result = lastCall.then(() => fn(...args))

    // `lastCall` will resolve after the backoff duration is over.
    lastCall = result
      .return(null) // Ignore return value of previous call.
      .catch(() => null) // Ignore errors.
      .delay(currentDelay)
      .tap(unqueueCall)

    return result
  }
}
{'fraction_non_alphanumeric': 0.11988672120830711, 'fraction_numerical': 0.010069225928256766, 'mean_word_length': 3.133940182054616, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2445117', 'n_tokens_mistral': 980, 'n_tokens_neox': 928, 'n_words': 301}