Azure Durable Functions操作CosmosDB大负载时异常处理失效问题
CosmosDB写入问题解决方案
问题梳理
- 单文档大小超2MB时抛出异常:
Microsoft.Azure.DocumentDB.Core: Message: {"Errors":["Request size is too large"]}
sys.getsizeof无法准确计算CosmosDB文档实际存储大小- 异常处理代码中的日志未触发,重试策略因负载大小固定完全无效
一、准确计算CosmosDB文档大小
sys.getsizeof仅计算Python内存对象大小,无法反映JSON序列化后的实际存储大小。正确计算方式是将文档序列化为UTF-8编码的JSON字符串,再统计字节数:
import json def calculate_cosmos_doc_size(document): # 序列化文档为JSON字符串,保留非ASCII字符 json_content = json.dumps(document, ensure_ascii=False) # 返回UTF-8编码后的字节数 return len(json_content.encode('utf-8'))
二、超大文档预处理
提前筛选出超过2MB的文档,单独路由到队列做后续处理(比如拆分字段、存储到Blob后存引用):
MAX_ALLOWED_SIZE = 2 * 1024 * 1024 # 2MB # 拆分正常文档与超大文档 normal_entities = [doc for doc in entities_document_list if calculate_cosmos_doc_size(doc) <= MAX_ALLOWED_SIZE] large_entities = [doc for doc in entities_document_list if calculate_cosmos_doc_size(doc) > MAX_ALLOWED_SIZE] # 写入正常文档到CosmosDB entitiesCollection.set(normal_entities) # 发送超大文档到队列待处理 queue_client.send_message(json.dumps(large_entities))
三、修复异常处理失效问题
异常日志未触发通常有以下几种原因及修复方式:
- 异步方法未加await:如果
set是异步方法,同步try-except无法捕获异常,需添加await:try: await entitiesCollection.set(entities_document_list) await classificationsCollection.set(classifications_document_list) await relatedAssetsCollection.set(related_assets_document_list) await lineageCollection.set(lineage_document_list) except Exception as err: logging.error(f"Saving to CosmosDB failed with error - {err}") - 重试策略吞掉异常:检查重试配置,确保不对
Request size is too large这类不可恢复异常重试,避免异常被重试框架拦截 - 日志级别配置错误:确认logging模块的级别设置为
ERROR或更低,否则错误日志无法输出
四、优化重试策略
针对大小超限这类不可恢复异常,直接跳过重试,只重试连接超时、服务暂时不可用等可恢复异常:
from tenacity import retry, stop_after_attempt, retry_if_exception_type def is_retryable_exception(exc): # 仅重试非大小超限的异常 return "Request size is too large" not in str(exc) @retry(stop=stop_after_attempt(3), retry=retry_if_exception_type(Exception), retry_error_callback=lambda state: None) async def save_to_cosmos(collection, docs): await collection.set(docs)
内容的提问来源于stack exchange,提问作者basquiatraphaeu
相关产品推荐
相关产品推荐

