{"version":3,"file":"flushController.mjs","names":[],"sources":["../../src/transport/flushController.ts"],"sourcesContent":["import { ONE_SECOND } from '@openobserve/js-core/time'\nimport type { Duration } from '@openobserve/js-core/time'\nimport type { PageMayExitEvent, PageExitReason } from '../browser/pageMayExitObservable'\nimport { isWorkerEnvironment } from '../tools/globalObject'\nimport { Observable } from '../tools/observable'\nimport type { TimeoutId } from '../tools/timer'\nimport { clearTimeout, setTimeout } from '../tools/timer'\nimport { RECOMMENDED_REQUEST_BYTES_LIMIT } from './httpRequest'\n\nexport type FlushReason = PageExitReason | 'duration_limit' | 'bytes_limit' | 'messages_limit' | 'session_expire'\n\n/**\n * flush automatically, aim to be lower than ALB connection timeout\n * to maximize connection reuse.\n */\nexport const FLUSH_DURATION_LIMIT = (30 * ONE_SECOND) as Duration\n\n/**\n * When using the SDK in a Worker Environment, we limit the batch size to 1 to ensure it can be sent\n * in a single event.\n */\nexport const MESSAGES_LIMIT = isWorkerEnvironment ? 1 : 50\n\nexport type FlushController = ReturnType<typeof createFlushController>\nexport interface FlushEvent {\n  reason: FlushReason\n  bytesCount: number\n  messagesCount: number\n}\n\ninterface FlushControllerOptions {\n  pageMayExitObservable: Observable<PageMayExitEvent>\n  sessionExpireObservable: Observable<void>\n}\n\n/**\n * Returns a \"flush controller\", responsible of notifying when flushing a pool of pending data needs\n * to happen. The implementation is designed to support both synchronous and asynchronous usages,\n * but relies on invariants described in each method documentation to keep a coherent state.\n */\nexport function createFlushController({ pageMayExitObservable, sessionExpireObservable }: FlushControllerOptions) {\n  let forcedFlushReason: FlushReason | undefined\n  const preparePageExitFlushObservable = new Observable<PageExitReason>()\n  const pageMayExitSubscription = pageMayExitObservable.subscribe((event) => {\n    forcedFlushReason = event.reason\n    try {\n      preparePageExitFlushObservable.notify(event.reason)\n    } finally {\n      forcedFlushReason = undefined\n    }\n    flush(event.reason)\n  })\n  const sessionExpireSubscription = sessionExpireObservable.subscribe(() => flush('session_expire'))\n\n  const flushObservable = new Observable<FlushEvent>(() => () => {\n    pageMayExitSubscription.unsubscribe()\n    sessionExpireSubscription.unsubscribe()\n  })\n\n  let currentBytesCount = 0\n  let currentMessagesCount = 0\n\n  function flush(flushReason: FlushReason) {\n    if (currentMessagesCount === 0) {\n      return\n    }\n\n    const messagesCount = currentMessagesCount\n    const bytesCount = currentBytesCount\n\n    currentMessagesCount = 0\n    currentBytesCount = 0\n    cancelDurationLimitTimeout()\n\n    flushObservable.notify({\n      reason: flushReason,\n      messagesCount,\n      bytesCount,\n    })\n  }\n\n  let durationLimitTimeoutId: TimeoutId | undefined\n  function scheduleDurationLimitTimeout() {\n    if (durationLimitTimeoutId === undefined) {\n      durationLimitTimeoutId = setTimeout(() => {\n        flush('duration_limit')\n      }, FLUSH_DURATION_LIMIT)\n    }\n  }\n\n  function cancelDurationLimitTimeout() {\n    clearTimeout(durationLimitTimeoutId)\n    durationLimitTimeoutId = undefined\n  }\n\n  return {\n    flushObservable,\n    preparePageExitFlushObservable,\n    get messagesCount() {\n      return currentMessagesCount\n    },\n\n    /**\n     * Notifies that a message will be added to a pool of pending messages waiting to be flushed.\n     *\n     * This function needs to be called synchronously, right before adding the message, so no flush\n     * event can happen after `notifyBeforeAddMessage` and before adding the message.\n     *\n     * @param estimatedMessageBytesCount - an estimation of the message bytes count once it is\n     * actually added.\n     */\n    notifyBeforeAddMessage(estimatedMessageBytesCount: number) {\n      if (currentBytesCount + estimatedMessageBytesCount >= RECOMMENDED_REQUEST_BYTES_LIMIT) {\n        flush(forcedFlushReason ?? 'bytes_limit')\n      }\n      // Consider the message to be added now rather than in `notifyAfterAddMessage`, because if no\n      // message was added yet and `notifyAfterAddMessage` is called asynchronously, we still want\n      // to notify when a flush is needed (for example on page exit).\n      currentMessagesCount += 1\n      currentBytesCount += estimatedMessageBytesCount\n      scheduleDurationLimitTimeout()\n    },\n\n    /**\n     * Notifies that a message *was* added to a pool of pending messages waiting to be flushed.\n     *\n     * This function can be called asynchronously after the message was added, but in this case it\n     * should not be called if a flush event occurred in between.\n     *\n     * @param messageBytesCountDiff - the difference between the estimated message bytes count and\n     * its actual bytes count once added to the pool.\n     */\n    notifyAfterAddMessage(messageBytesCountDiff = 0) {\n      currentBytesCount += messageBytesCountDiff\n\n      if (currentMessagesCount >= MESSAGES_LIMIT) {\n        flush(forcedFlushReason ?? 'messages_limit')\n      } else if (currentBytesCount >= RECOMMENDED_REQUEST_BYTES_LIMIT) {\n        flush(forcedFlushReason ?? 'bytes_limit')\n      }\n    },\n  }\n}\n"],"mappings":";;;;;;;;;;AAeA,MAAa,uBAAwB,KAAK;;;;;AAM1C,MAAa,iBAAiB,sBAAsB,IAAI;;;;;;AAmBxD,SAAgB,sBAAsB,EAAE,uBAAuB,2BAAmD;CAChH,IAAI;CACJ,MAAM,iCAAiC,IAAI,WAA2B;CACtE,MAAM,0BAA0B,sBAAsB,WAAW,UAAU;EACzE,oBAAoB,MAAM;EAC1B,IAAI;GACF,+BAA+B,OAAO,MAAM,MAAM;EACpD,UAAU;GACR,oBAAoB,KAAA;EACtB;EACA,MAAM,MAAM,MAAM;CACpB,CAAC;CACD,MAAM,4BAA4B,wBAAwB,gBAAgB,MAAM,gBAAgB,CAAC;CAEjG,MAAM,kBAAkB,IAAI,uBAAmC;EAC7D,wBAAwB,YAAY;EACpC,0BAA0B,YAAY;CACxC,CAAC;CAED,IAAI,oBAAoB;CACxB,IAAI,uBAAuB;CAE3B,SAAS,MAAM,aAA0B;EACvC,IAAI,yBAAyB,GAC3B;EAGF,MAAM,gBAAgB;EACtB,MAAM,aAAa;EAEnB,uBAAuB;EACvB,oBAAoB;EACpB,2BAA2B;EAE3B,gBAAgB,OAAO;GACrB,QAAQ;GACR;GACA;EACF,CAAC;CACH;CAEA,IAAI;CACJ,SAAS,+BAA+B;EACtC,IAAI,2BAA2B,KAAA,GAC7B,yBAAyB,iBAAiB;GACxC,MAAM,gBAAgB;EACxB,GAAG,oBAAoB;CAE3B;CAEA,SAAS,6BAA6B;EACpC,aAAa,sBAAsB;EACnC,yBAAyB,KAAA;CAC3B;CAEA,OAAO;EACL;EACA;EACA,IAAI,gBAAgB;GAClB,OAAO;EACT;;;;;;;;;;EAWA,uBAAuB,4BAAoC;GACzD,IAAI,oBAAoB,8BAA8B,iCACpD,MAAM,qBAAqB,aAAa;GAK1C,wBAAwB;GACxB,qBAAqB;GACrB,6BAA6B;EAC/B;;;;;;;;;;EAWA,sBAAsB,wBAAwB,GAAG;GAC/C,qBAAqB;GAErB,IAAI,wBAAwB,gBAC1B,MAAM,qBAAqB,gBAAgB;QACtC,IAAI,qBAAqB,iCAC9B,MAAM,qBAAqB,aAAa;EAE5C;CACF;AACF"}