Как повторить выполнение задачи Django Celery при возникновении внутренней ошибки сервера?

I am trying to use Celery to send anywhere from 1 to about 25 consecutive requests to a third-party API. The measure of success is whether I get a URL back in the response payload: response_json["data"]["url"]. Celery or not, sometimes I get the data I expect, and sometimes I don't.

Я решил поэкспериментировать с Celery, чтобы повторить вызов API, используя при этом преимущества встроенного экспоненциального отката, который, казалось бы, идеально подходит для моих нужд, но я испытываю трудности с его реализацией.

<

Вот пример одного из нескольких подобных подходов, которые я пробовал:

@shared_task(autoretry_for=(Exception), retry_backoff=True, retry_backoff_max=120)
def third_party_api_request(payload, api_url, headers):
    response = requests.request("POST", api_url, headers=headers, data=payload)
    response_json = response.json()
    return response_json["data"]["url"]

# output:
Internal Server Error:
-- snip --
    autoretry_for = tuple(
TypeError: 'type' object is not iterable

Другой подход, который я пробовал:

@shared_task(bind=True)
def third_party_api_request(self, payload, api_url, headers):
    try:
        response = requests.request("POST", api_url, headers=headers, data=payload)
        response_json = response.json()
        return response_json["data"]["url"]
    except TypeError as exc:
        logger.error("Error sending request to API: %s", exc)
        raise self.retry(exc=exc)

# output:
ERROR 2022-04-22 17:31:40,131 tasks 72780 123145528369152 Error sending request to API: 'NoneType' object is not subscriptable
Internal Server Error:
-- snip --
TypeError: 'NoneType' object is not subscriptable
-- snip --
    raise ret
celery.exceptions.Retry: Retry in 180s: TypeError("'NoneType' object is not subscriptable")
ERROR 2022-04-22 17:31:40,409 log 72780 123145528369152 Internal Server Error:
-- snip --
TypeError: 'NoneType' object is not subscriptable
-- snip --
   raise ret
celery.exceptions.Retry: Retry in 180s: TypeError("'NoneType' object is not subscriptable")

И еще один подход, с похожими результатами:

@shared_task(autoretry_for=(TypeError), retry_backoff=True, retry_backoff_max=120)
def send_http_request_to_proctoru_task(payload, api_url, headers):
    response = requests.request("POST", api_url, headers=headers, data=payload)
    response_json = response.json()
    try:
        return response_json["data"]["url"]
    except TypeError:
        logger.error("API response: %s", response_json)
        raise

Проблема заключалась в том, что я неправильно разместил оператор возврата. Мне предстоит еще много доработок, но следующий код решает проблему в вопросе, который я задал ранее сегодня. Я читал сообщения, документацию и статьи в течение нескольких дней, и я хотел бы приписать себе все заслуги, но именно эта запись в блоге помогла мне осознать мою ошибку: https://testdriven.io/blog/retrying-failed-celery-tasks/.

@shared_task(name="send_http_request_to_proctoru_task", bind=True, max_retries=6)
def send_http_request_to_proctoru_task(self, api_url, headers, payload):
    try:
        response = requests.request("POST", api_url, headers=headers, data=payload)
        response_json = response.json()
        if response_json["response_code"] == 2:
            raise Exception()

        return response_json["data"]["url"]
    except Exception as exc:
        logger.warning("Exception raised. Executing retry %s" % self.request.retries)
        raise self.retry(exc=exc, countdown=2 ** self.request.retries)
Вернуться на верх