2011-06-27 58 views
17

Tôi đang cố gắng sử dụng dịch vụ web không đồng bộ vì mất tối đa 45 giây để trả lại. Thật không may, dịch vụ web này cũng phần nào không đáng tin cậy và có thể ném lỗi. Tôi đã thiết lập django-celery và thực hiện các tác vụ của mình, hoạt động tốt cho đến khi tác vụ không thành công vượt quá max_retries.Khôi phục từ tác vụ không thành công ngoài max_retries

Dưới đây là những gì tôi có cho đến nay:

@task(default_retry_delay=5, max_retries=10) 
def request(xml): 
    try: 
     server = Client('https://www.whatever.net/RealTimeService.asmx?wsdl') 
     xml = server.service.RunRealTimeXML(
      username=settings.WS_USERNAME, 
      password=settings.WS_PASSWORD, 
      xml=xml 
     ) 
    except Exception, e: 
     result = Result(celery_id=request.request.id, details=e.reason, status="i") 
     result.save() 
     try: 
      return request.retry(exc=e) 
     except MaxRetriesExceededError, e: 
      result = Result(celery_id=request.request.id, details="Max Retries Exceeded", status="f") 
      result.save() 
      raise 
    result = Result(celery_id=request.request.id, details=xml, status="s") 
    result.save() 
    return result 

Thật không may, MaxRetriesExceededError không được ném bởi retry(), vì vậy tôi không chắc chắn làm thế nào để xử lý sự thất bại của nhiệm vụ này. Django đã trả lại HTML cho khách hàng và tôi đang kiểm tra nội dung của Result qua AJAX, điều này không bao giờ bị lỗi đầy đủ trạng thái f.

Vì vậy, câu hỏi đặt ra là: Làm cách nào để cập nhật cơ sở dữ liệu của tôi khi nhiệm vụ Celery vượt quá max_retries?

Trả lời

14

Bạn có thể ghi đè lên các phương pháp after_return của lớp nhiệm vụ cần tây, phương pháp này được gọi là sau khi thực hiện nhiệm vụ bất cứ điều gì là tình trạng ret (SUCCESS, FAILED, retry)

class MyTask(celery.task.Task) 

    def run(self, xml, **kwargs) 
     #Your stuffs here 

    def after_return(self, status, retval, task_id, args, kwargs, einfo=None): 
     if self.max_retries == int(kwargs['task_retries']): 
      #If max retries are equals to task retries do something 
     if status == "FAILURE": 
      #You can do also something if the tasks fail instead of check the retries 

http://readthedocs.org/docs/celery/en/latest/reference/celery.task.base.html#celery.task.base.BaseTask.after_return

http://celery.readthedocs.org/en/latest/reference/celery.app.task.html?highlight=after_return#celery.app.task.Task.after_return

+0

Vì liên kết rõ ràng là lỗi thời bây giờ, [ở đây là một cái mới] (http://celery.readthedocs.org/en/latest/reference/celery.app.task.html?highlight=after_return#celery.app.task.Task.after_return) – rschwieb

+0

Cảm ơn, câu trả lời đã được cập nhật. –

15

với phiên bản 2.3.2 Cần tây phương pháp này đã làm việc tốt cho tôi:

class MyTask(celery.task.Task): 
    abstract = True 

    def after_return(self, status, retval, task_id, args, kwargs, einfo): 
     if self.max_retries == self.request.retries: 
      #If max retries is equal to task retries do something 

@task(base=MyTask, default_retry_delay=5, max_retries=10) 
def request(xml): 
    #Your stuff here 
6

Tôi sẽ thực hiện điều này ngay bây giờ, hãy tha thứ cho tôi công việc phân lớp nhiệm vụ và dễ hiểu.

# auto-retry with delay as defined below. After that, hook is disabled. 
@celery.shared_task(bind=True, max_retries=5, default_retry_delay=300) 
def post_data(self, hook_object_id, url, event, payload): 
    headers = {'Content-type': 'application/json'} 
    try: 
     r = requests.post(url, data=payload, headers=headers) 
     r.raise_for_status() 
    except requests.exceptions.RequestException as e: 
     if self.request.retries >= self.max_retries: 
      log.warning("Auto-deactivating webhook %s for event %s", hook_object_id, event) 
      Webhook.objects.filter(object_id=hook_object_id).update(active=False) 
      return False 
     raise self.retry(exc=e) 
    return True 
8

Vấn đề là cần tây đang cố gắng tăng lại ngoại lệ bạn đã vượt qua khi đạt đến giới hạn thử lại. Các mã để làm điều này tái huy động là ở đây: https://github.com/celery/celery/blob/v3.1.20/celery/app/task.py#L673-L681

Cách đơn giản nhất xung quanh này là chỉ cần không có cần tây quản lý ngoại lệ của bạn tại tất cả:

@task(max_retries=10) 
def mytask(): 
    try: 
     do_the_thing() 
    except Exception as e: 
     try: 
      mytask.retry() 
     except MaxRetriesExceededError: 
      do_something_to_handle_the_error() 
      logger.exception(e) 
+1

Đây là giải pháp phù hợp cho vấn đề ban đầu. –

Các vấn đề liên quan