AZ_NODISCARD az_result az_http_pipeline_policy_retry()

in sdk/src/azure/core/az_http_policy_retry.c [153:223]


AZ_NODISCARD az_result az_http_pipeline_policy_retry(
    _az_http_policy* ref_policies,
    void* ref_options,
    az_http_request* ref_request,
    az_http_response* ref_response)
{
  az_http_policy_retry_options const* const retry_options
      = (az_http_policy_retry_options const*)ref_options;

  int32_t const max_retries = retry_options->max_retries;
  int32_t const retry_delay_msec = retry_options->retry_delay_msec;
  int32_t const max_retry_delay_msec = retry_options->max_retry_delay_msec;

  _az_RETURN_IF_FAILED(_az_http_request_mark_retry_headers_start(ref_request));

  az_context* const context = ref_request->_internal.context;

  bool const should_log = _az_LOG_SHOULD_WRITE(AZ_LOG_HTTP_RETRY);
  az_result result = AZ_OK;
  int32_t attempt = 1;
  while (true)
  {
    _az_RETURN_IF_FAILED(
        az_http_response_init(ref_response, ref_response->_internal.http_response));
    _az_RETURN_IF_FAILED(_az_http_request_remove_retry_headers(ref_request));

    result = _az_http_pipeline_nextpolicy(ref_policies, ref_request, ref_response);

    // Even HTTP 429, or 502 are expected to be AZ_OK, so the failed result is not retriable.
    if (attempt > max_retries || az_result_failed(result))
    {
      return result;
    }

    int32_t retry_after_msec = -1;
    bool should_retry = false;
    az_http_response response_copy = *ref_response;

    _az_RETURN_IF_FAILED(
        _az_http_policy_retry_get_retry_after(&response_copy, &should_retry, &retry_after_msec));

    if (!should_retry)
    {
      return result;
    }

    ++attempt;

    if (retry_after_msec < 0)
    { // there wasn't any kind of "retry-after" response header
      retry_after_msec = _az_retry_calc_delay(attempt, retry_delay_msec, max_retry_delay_msec);
    }

    if (should_log)
    {
      _az_http_policy_retry_log(attempt, retry_after_msec);
    }

    _az_RETURN_IF_FAILED(az_platform_sleep_msec(retry_after_msec));

    if (context != NULL)
    {
      int64_t clock = 0;
      _az_RETURN_IF_FAILED(az_platform_clock_msec(&clock));
      if (az_context_has_expired(context, clock))
      {
        return AZ_ERROR_CANCELED;
      }
    }
  }
}