M4: implement n8n automation
Outbox dispatcher (background thread, FOR UPDATE SKIP LOCKED claim, exponential backoff, no transaction held during HTTP I/O). n8n callback endpoint with shared-secret auth and idempotency by event ID. Automation nav + UI with manual retry. 49 backend tests passing, ruff clean. Fixed a crash-on-redelivery bug in seeded outbox payloads and made the dispatcher defensive against malformed payloads. Verified the full live round trip against a real n8n instance: return -> outbox -> dispatcher -> n8n workflow -> callback -> succeeded, including the S5 failed-retry demo scenario.
This commit is contained in:
+24
-2
@@ -1,15 +1,35 @@
|
||||
import uuid
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from app.api.routers import audit, bookings, dashboard, data_quality, demo, vehicles
|
||||
from app.api.routers import (
|
||||
audit,
|
||||
bookings,
|
||||
dashboard,
|
||||
data_quality,
|
||||
demo,
|
||||
integrations,
|
||||
vehicles,
|
||||
workflows,
|
||||
)
|
||||
from app.core.config import get_settings
|
||||
from app.core.errors import AppError, error_body
|
||||
from app.services.dispatcher import start_background_dispatcher, stop_background_dispatcher
|
||||
|
||||
settings = get_settings()
|
||||
app = FastAPI(title="MobilityOps API", version="0.1.0")
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(_app: FastAPI):
|
||||
start_background_dispatcher()
|
||||
yield
|
||||
stop_background_dispatcher()
|
||||
|
||||
|
||||
app = FastAPI(title="MobilityOps API", version="0.1.0", lifespan=lifespan)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
@@ -62,3 +82,5 @@ app.include_router(vehicles.router)
|
||||
app.include_router(bookings.router)
|
||||
app.include_router(audit.router)
|
||||
app.include_router(data_quality.router)
|
||||
app.include_router(workflows.router)
|
||||
app.include_router(integrations.router)
|
||||
|
||||
Reference in New Issue
Block a user