async tryFlush()

in projects/alloydb-autoscaler/src/autoscaler-core/common/open-telemetry-meter-provider.ts [182:272]


  async tryFlush() {
    if (OpenTelemetryMeterProvider.pendingInit) {
      await OpenTelemetryMeterProvider.pendingInit.promise;
    }

    if (
      !OpenTelemetryMeterProvider.isTryFlushEnabled ||
      !OpenTelemetryMeterProvider.exporterParams?.FLUSH_ENABLED
    ) {
      // Flushing disabled, do nothing!
      return;
    }

    // Avoid simultaneous flushing.
    if (OpenTelemetryMeterProvider.pendingFlush) {
      await OpenTelemetryMeterProvider.pendingFlush.promise;
      return;
    }
    OpenTelemetryMeterProvider.pendingFlush = promiseWithResolvers();

    if (
      !OpenTelemetryMeterProvider.exporterParams ||
      !OpenTelemetryMeterProvider.meterProvider
    ) {
      // This should not happen since we are awaiting the init.
      // Done to avoid typing issues.
      throw new Error('Counters have not been initialized.');
    }

    try {
      await OpenTelemetryMeterProvider.waitUntilNextFlushTime();

      // OpenTelemetry's forceFlush() will always succeed, even if the backend
      // fails and reports an error...
      //
      // So we use the OpenTelemetry Global Error Handler installed above
      // to keep a count of the number of errors reported, and if an error
      // is reported during a flush, we wait a while and try again.
      // Not perfect, but the best we can do.
      //
      // To avoid end-users seeing these errors, we supress error messages
      // until the very last flush attempt.
      //
      // Note that if the OpenTelemetry metrics are exported to Google Cloud
      // Monitoring, the first time a counter is used, it will fail to be
      // exported and will need to be retried.
      let attempts =
        OpenTelemetryMeterProvider.exporterParams.FLUSH_MAX_ATTEMPTS;
      while (attempts > 0) {
        const beforeFlushErrorCount =
          OpenTelemetryMeterProvider.openTelemetryErrorCount;

        // Suppress OTEL Diag error messages on all but the last flush attempt.
        OpenTelemetryMeterProvider.diagPinoLogger.suppressErrors = attempts > 1;
        await OpenTelemetryMeterProvider.meterProvider.forceFlush();
        OpenTelemetryMeterProvider.diagPinoLogger.suppressErrors = false;

        OpenTelemetryMeterProvider.lastForceFlushTime = Date.now();

        const afterFlushErrorCount =
          OpenTelemetryMeterProvider.openTelemetryErrorCount;
        if (beforeFlushErrorCount === afterFlushErrorCount) {
          // Success!
          return;
        }

        OpenTelemetryMeterProvider.diagPinoLogger.warn(
          'Opentelemetry reported errors during flushing, retrying.'
        );
        await sleep(
          OpenTelemetryMeterProvider.exporterParams.FLUSH_MIN_INTERVAL
        );
        attempts--;
      }

      if (attempts <= 0) {
        OpenTelemetryMeterProvider.diagPinoLogger.error(
          'Failed to flush counters after ' +
            OpenTelemetryMeterProvider.exporterParams.FLUSH_MAX_ATTEMPTS +
            'attempts - see OpenTelemetry logging'
        );
      }
    } catch (e) {
      OpenTelemetryMeterProvider.diagPinoLogger.error(
        `Error while flushing counters: ${e}`
      );
    } finally {
      OpenTelemetryMeterProvider.pendingFlush.resolve(null);
      OpenTelemetryMeterProvider.pendingFlush = null;
    }
  }