getSinglePingFn()

in marketing-analytics/activation/common-libs/nodejs-common/src/apis/measurement_protocol_ga4.js [91:175]


  getSinglePingFn(config) {
    /**
     * Sends a hit to Measurement Protocol GA4.
     * @param {!Array<string>} lines Data for single request. It should be
     *     guaranteed that it doesn't exceed quota limitation.
     * @param {string} batchId The tag for log.
     * @return {!BatchResult}
     */
    return async (lines, batchId) => {
      const line = lines[0]; // Each request contains one record only.
      if (lines.length > 1) {
        this.logger.warn(
            "Only one line data expected. Will only send the first line.");
      }
      const hit = lodash.merge({}, config.requestBody, JSON.parse(line));

      const requestOptions = {
        method: 'POST',
        url: `${BASE_URL}${this.path}`,
        params: config.queryString,
        paramsSerializer: (params) => {
          return Object.keys(params)
              .map((param) => `${param}=${params[param]}`)
              .join('&');
        },
        validateStatus: () => true,
        body: JSON.stringify(hit),
        headers: { 'User-Agent': 'Tentacles/MeasurementProtocol-GA4' },
      };
      /** @type {BatchResult} */ const batchResult = {
        numberOfLines: lines.length,
      };
      let retriedTimes = 0;
      let response;
      while (retriedTimes <= RETRY_TIMES) {
        try {
          response = await request(requestOptions);
          if (response.status < 500) break; // Only retry when server errors.
          this.logger.warn('Got a 5XX error', response);
        } catch (error) {
          this.logger.warn('Got an error', error);
          if (retriedTimes === RETRY_TIMES) {
            this.logger.error('Maximum retry times exceeded.');
            batchResult.result = false;
            batchResult.errors = [error.toString()];
            break;
          }
        }
        retriedTimes++;
        await wait(retriedTimes * 1000);
        this.logger.warn('Will retry now...');
      };
      if (response) {
        this.logger.debug('Configuration:', config);
        this.logger.debug('Input Data:   ', lines);
        this.logger.debug(`Batch[${batchId}] status: ${response.status}`);
        this.logger.debug(response.data);
        // There is not enough information from the non-debug mode.
        if (!this.debugMode) {
          if (response.status >= 200 && response.status < 300) {
            batchResult.result = true;
          } else {
            batchResult.result = false;
            const errorMessage =
              `MP GA4 [${batchId}] http status ${response.status}.`;
            this.logger.error(errorMessage, line);
            batchResult.errors = [errorMessage];
          }
        } else {
          if (response.data.validationMessages.length === 0) {
            batchResult.result = true;
          } else {
            batchResult.result = false;
            batchResult.errors = response.data.validationMessages.map(
              ({ description }) => description);
          }
        }
      }
      if (!batchResult.result) {
        batchResult.failedLines = [line];
        batchResult.groupedFailed = { [batchResult.errors.join()]: [line] };
      }
      return batchResult;
    };
  };