// TODO consider more events
// e.g. uncaught exceptions, SIGUSR1, SIGUSR2, SIGTERM
const events = ["beforeExit", "exit", "SIGINT"]

/**
 * Call the function `cb`, ensuring that the `cleanup` function is called
 * on any error or interrupt.
 *
 * @param cleanup the asynchronous cleanup function
 * @param cb the function to clean up after
 */
export async function withAsyncCleanup(
  cleanup: () => Promise<void>,
  cb: () => Promise<void>
): Promise<void> {
  // Cleanup callbacks must be synchronous,
  // so trigger an async function that exits the process
  const cleanupAndExit = async (status: number = 0) => {
    // cleanup and then trigger an exit
    await cleanup()
    process.exit(status)
  }

  for (const event of events) {
    process.on(event, cleanupAndExit)
  }

  try {
    await cb()
  } finally {
    await cleanup()
    // After running the cleanup, remove the listeners so they don't hit the limit
    for (const event of events) {
      process.removeListener(event, cleanupAndExit)
    }
  }
}