fetch = async (remote, options) => {
  let hasNewDatabase = false
  let isFetching = false
  let fetchOnReconnect = false

  const doFetch = async () => {
    if (isFetching) {
      return
    }
    isFetching = true
    hasNewDatabase = false
    const t0 = Date.now()
    return fetchAndMerge(remote, options)
      .then(() => log.info(t0, `Fetched remote from ${remote.url}`))
      .catch(err => {
        log.error(err, `Failed to fetch from remote ${remote.url}: ${err}`)
        return Promise.reject(err)
      })
      .finally(() => {
        isFetching = false
        if (hasNewDatabase) {
          return doFetch()
        }
      })
  }

  const isDatabaseReloadEvent = event => event?.data?.type == 'server' && event?.data?.action == 'databaseReloaded'

  const onEvent = (event) => {
    if (isDatabaseReloadEvent(event)) {
      log.debug(event, `Receiving database reload event`)
      log.info(`Fetching remote due remote database change`)
      hasNewDatabase = true
      doFetch().catch(err => {
        log.warn(err, `Failed to fetch: ${err}`)
      })
    } else if (fetchOnReconnect && event?.data?.type == 'connect') {
      log.info(`Fetching remote due reconnection to remote`)
      fetchOnReconnect = false
      doFetch().catch(err => {
        log.warn(err, `Failed to fetch: ${err}`)
      })
    }
  }

  return new Promise((resolve, reject) => {
    if (remote.watch) {
      log.info(`Fetch remote in watch mode from ${remote.url}`)
      connectEventStream(remote, onEvent)
      doFetch().catch(err => {
        log.warn(err, `Failed to fetch remote ${err}. Retry fetch on reconnection`)
        fetchOnReconnect = true
      })
      process.once('SIGINT', () => {
        log.info(`Received SIGINT. Stop watch mode`)
        resolve()
      })
    } else {
      doFetch().then(resolve).catch(reject)
    }
  })
}
@param {import('./types').Remote} remote
@param {*} options