TradeFlowAI / src /tasks /submit_tasks.py
muhammadghiffari's picture
Deploy TradeFlow API to HF
db4ba8d
Raw
History Blame Contribute Delete
3.41 kB
"""
TradeFlow AI — Wired Submission Tasks (Phase 4)
"""
from __future__ import annotations
import asyncio
import uuid
import structlog
from celery import Task
from .celery_app import celery_app
log = structlog.get_logger()
@celery_app.task(
bind=True,
queue="high",
max_retries=5,
default_retry_delay=60,
autoretry_for=(Exception,),
retry_backoff=True,
retry_backoff_max=600,
)
def submit_to_ceisa(self: Task, batch_id: str, submission_id: str) -> dict:
"""
Submit declaration to CEISA 4.0.
Auto-retries with exponential backoff for AUTO_RECOVERABLE errors.
"""
from ..services.ceisa_svc import ceisa_service
log.info("Submitting to CEISA", batch_id=batch_id, attempt=self.request.retries + 1)
# In full impl: fetch extracted_data from DB
extracted_data: dict = {}
idempotency_key = str(uuid.uuid4())
result = asyncio.get_event_loop().run_until_complete(
ceisa_service.submit(
batch_id=batch_id,
extracted_data=extracted_data,
submission_id=submission_id,
idempotency_key=idempotency_key,
attempt=self.request.retries + 1,
)
)
classification = result.get("error_classification")
if result["status"] in ("rejected", "failed"):
if classification == "AUTO_RECOVERABLE" and self.request.retries < self.max_retries:
# Attempt auto-fix then resubmit
fixed = asyncio.get_event_loop().run_until_complete(
ceisa_service.auto_fix_and_resubmit(
batch_id=batch_id,
extracted_data=extracted_data,
error_code=result.get("error_code", ""),
original_submission_id=submission_id,
)
)
return fixed
elif classification == "OPERATOR_REQUIRED":
log.warning("Operator action required", batch_id=batch_id, code=result.get("error_code"))
# Enqueue human review via Supabase Realtime notification
return result
else:
log.error("Admin escalation required", batch_id=batch_id)
return result
# On success → enqueue blockchain anchor on critical queue
if result["status"] in ("accepted", "processing"):
anchor_blockchain.apply_async(args=[batch_id], queue="critical")
return result
@celery_app.task(bind=True, queue="critical", max_retries=3, default_retry_delay=30)
def anchor_blockchain(self: Task, batch_id: str) -> dict:
"""Anchor submission hash to Polygon."""
from ..services.blockchain_svc import blockchain_service
log.info("Anchoring to blockchain", batch_id=batch_id)
try:
result = asyncio.get_event_loop().run_until_complete(
blockchain_service.anchor(
batch_id=batch_id,
payload={"batch_id": batch_id},
document_hashes=[],
)
)
log.info("Blockchain anchor complete", batch_id=batch_id, tx=result.get("tx_hash"))
return result
except Exception as exc:
log.error("Blockchain anchor failed", error=str(exc))
raise self.retry(exc=exc)
@celery_app.task(bind=True, queue="high")
def process_ceisa_response(self: Task, batch_id: str) -> None:
"""Handle async CEISA webhook response."""
log.info("Processing CEISA response", batch_id=batch_id)