feature/capturar errores, evitar duplicados, eliminar manejar nuevas flags para descargar datos de vucem
This commit is contained in:
@@ -203,6 +203,7 @@ async def change_edocument_status(edoc: dict, status: bool, pedimento: dict):
|
||||
data = {
|
||||
"id": edoc.get("id"),
|
||||
"acuse_descargado": status,
|
||||
"acuse_estado": "descargado" if status else "pendiente",
|
||||
"numero_edocument": edoc.get("numero_edocument"),
|
||||
"pedimento": pedimento.get("id"),
|
||||
"organizacion": pedimento.get("organizacion"),
|
||||
@@ -210,6 +211,36 @@ async def change_edocument_status(edoc: dict, status: bool, pedimento: dict):
|
||||
|
||||
response = await acuse_rest_controller.put_edocument(edocument_id=edoc.get("id"), data=data)
|
||||
|
||||
# Nunca reportar éxito si el estatus no quedó persistido (T2026-05-027)
|
||||
if response is None:
|
||||
logger.error(f"No se pudo actualizar el estatus del acuse del EDocument {edoc.get('numero_edocument')} en la API")
|
||||
raise Exception(f"Fallo al actualizar el estatus del acuse del EDocument {edoc.get('numero_edocument')}")
|
||||
|
||||
return response
|
||||
|
||||
|
||||
async def marcar_error_acuse(edoc: dict, pedimento: dict, mensaje: str, definitivo: bool = False):
|
||||
"""
|
||||
Reporta un fallo de descarga del acuse al registro de negocio (T2026-05-027).
|
||||
|
||||
- definitivo=False (fallo transitorio): solo registra ultimo_error; el registro
|
||||
permanece 'pendiente' y el tope de intentos automáticos del backend gobierna
|
||||
la transición a 'error'.
|
||||
- definitivo=True (fallo permanente): transiciona de inmediato a 'error';
|
||||
queda fuera del ciclo automático, solo reproceso manual o reset.
|
||||
"""
|
||||
data = {
|
||||
"id": edoc.get("id"),
|
||||
"ultimo_error": (mensaje or "Error de descarga en VUCEM")[:2000],
|
||||
"numero_edocument": edoc.get("numero_edocument"),
|
||||
"pedimento": pedimento.get("id"),
|
||||
"organizacion": pedimento.get("organizacion"),
|
||||
}
|
||||
if definitivo:
|
||||
data["acuse_estado"] = "error"
|
||||
response = await acuse_rest_controller.put_edocument(edocument_id=edoc.get("id"), data=data)
|
||||
if response is None:
|
||||
logger.error(f"No se pudo registrar el error del acuse del EDocument {edoc.get('numero_edocument')} en la API")
|
||||
return response
|
||||
|
||||
def _decode_acuse_base64_content(base64_content): # Testeado
|
||||
|
||||
@@ -6,9 +6,13 @@ from typing import Dict, Any
|
||||
from contextlib import asynccontextmanager
|
||||
from fastapi import HTTPException
|
||||
|
||||
from .services import obtener_acuse
|
||||
from .services import obtener_acuse, marcar_error_acuse
|
||||
from api.api_v2.modules.tasks.services import register_task, update_task
|
||||
|
||||
# Reintentos internos del worker: pertenecen al MISMO intento orquestado y no
|
||||
# incrementan el contador de intentos del backend (T2026-05-027)
|
||||
WORKER_MAX_RETRIES = 2
|
||||
|
||||
|
||||
@celery_app.task(bind=True)
|
||||
def process_acuse_request(self, acuse_request: Dict[str, Any]) -> Dict[str, Any]:
|
||||
@@ -20,23 +24,25 @@ def process_acuse_request(self, acuse_request: Dict[str, Any]) -> Dict[str, Any]
|
||||
pedimento_id = pedimento_info.get('id')
|
||||
organizacion_id = pedimento_info.get('organizacion')
|
||||
pedimento_app = pedimento_info.get('pedimento_app', 'N/A')
|
||||
|
||||
edoc_info = acuse_request.get('edoc', {})
|
||||
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
|
||||
try:
|
||||
# Registrar el inicio de la tarea
|
||||
logging.info(f"[ACUSE] Registrando inicio de tarea {task_id}")
|
||||
loop.run_until_complete(
|
||||
register_task(
|
||||
task_id=task_id,
|
||||
status="submitted",
|
||||
message=f"Iniciando proceso de acuse para pedimento {pedimento_app}",
|
||||
pedimento_id=pedimento_id,
|
||||
organizacion_id=organizacion_id,
|
||||
servicio=6 # 6 corresponde a "Acuse"
|
||||
# Registrar el inicio de la tarea (solo en la primera ejecución, no en reintentos)
|
||||
if self.request.retries == 0:
|
||||
logging.info(f"[ACUSE] Registrando inicio de tarea {task_id}")
|
||||
loop.run_until_complete(
|
||||
register_task(
|
||||
task_id=task_id,
|
||||
status="submitted",
|
||||
message=f"Iniciando proceso de acuse para pedimento {pedimento_app}",
|
||||
pedimento_id=pedimento_id,
|
||||
organizacion_id=organizacion_id,
|
||||
servicio=6 # 6 corresponde a "Acuse"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# Esperar un momento breve para asegurar que el registro se complete
|
||||
import time
|
||||
@@ -76,6 +82,22 @@ def process_acuse_request(self, acuse_request: Dict[str, Any]) -> Dict[str, Any]
|
||||
# En caso de error, actualizar estado
|
||||
error_message = f"Error al procesar acuse para pedimento {pedimento_app}: {str(e)}"
|
||||
logging.error(error_message)
|
||||
|
||||
# Reintento interno del worker para fallos transitorios (red, timeout):
|
||||
# mismo intento orquestado, NO incrementa el contador del backend
|
||||
if not isinstance(e, HTTPException) and self.request.retries < WORKER_MAX_RETRIES:
|
||||
raise self.retry(exc=e, countdown=60 * (self.request.retries + 1))
|
||||
|
||||
# Fallo definitivo de este intento: registrar el detalle en el registro de
|
||||
# negocio. Permanece 'pendiente'; el tope de intentos automáticos del
|
||||
# backend (MAX_INTENTOS_AUTO) gobierna la transición a 'error'.
|
||||
try:
|
||||
loop.run_until_complete(
|
||||
marcar_error_acuse(edoc_info, pedimento_info, error_message, definitivo=False)
|
||||
)
|
||||
except Exception as report_error:
|
||||
logging.error(f"No se pudo registrar el error en el registro de negocio: {report_error}")
|
||||
|
||||
try:
|
||||
loop.run_until_complete(
|
||||
update_task(
|
||||
|
||||
Reference in New Issue
Block a user