Celery定时任务报错:AsyncResult对象无法JSON序列化
解决Celery定时任务JSON序列化错误问题
错误原因
报错EncodeError(TypeError('Object of type AsyncResult is not JSON serializable'))的核心原因:
make_requests.delay()返回的是Celery的AsyncResult对象,你错误调用了单个AsyncResult的collect()方法(该方法仅适用于group任务结果),最终导致返回的列表包含不可JSON序列化的对象。- Celery要求任务返回值必须是JSON可序列化的基本类型(如字符串、整数、列表、字典等),
AsyncResult对象本身不支持JSON序列化。
解决方法
根据你的需求选择对应方案:
方案1:收集所有子任务的返回值
如果需要获取make_requests返回的整数结果,需等待子任务完成并提取返回值:
@shared_task() def periodic_exctract_urls(): print(f"{datetime.datetime.now()} Start periodic_exctract_urls") celery_results = [] film_name_queries = SearchQuery.objects.filter(is_site_search=False) url_queries = SearchQuery.objects.filter(is_site_search=True) for film in film_name_queries: celery_results.append(make_requests.delay(str(film.name))) for url in url_queries: for film in film_name_queries: celery_results.append(make_requests.delay( f"site:{url.name} {film.name}" )) task_results = [] for result in celery_results: try: # 获取子任务返回值,可设置超时时间避免阻塞 res = result.get(timeout=30) task_results.append(res) except Exception as e: # 处理任务执行异常,可根据需求调整 print(f"子任务执行失败: {e}") task_results.append(None) return task_results
方案2:仅收集子任务ID
如果只需要记录子任务的ID,直接提取AsyncResult的id属性即可(字符串类型支持JSON序列化):
@shared_task() def periodic_exctract_urls(): print(f"{datetime.datetime.now()} Start periodic_exctract_urls") celery_results = [] film_name_queries = SearchQuery.objects.filter(is_site_search=False) url_queries = SearchQuery.objects.filter(is_site_search=True) for film in film_name_queries: celery_results.append(make_requests.delay(str(film.name))) for url in url_queries: for film in film_name_queries: celery_results.append(make_requests.delay( f"site:{url.name} {film.name}" )) # 提取所有子任务ID task_ids = [result.id for result in celery_results] return task_ids
关键注意事项
- 禁止在Celery任务返回值中包含
AsyncResult等Celery内部对象,必须确保返回值是JSON可序列化的基本类型。 - 使用
result.get()时务必添加异常处理,避免主任务因子任务执行失败、超时等情况崩溃。 collect()方法仅用于group任务的结果集合,单个AsyncResult对象不要调用该方法。
内容的提问来源于stack exchange,提问作者mascai
相关产品推荐
相关产品推荐

