87 lines
5.2 KiB
Markdown
87 lines
5.2 KiB
Markdown
# Aceptación durable de eventos — T09
|
||
|
||
Implementado `POST /api/v1/requests/{id}/events`, habilitado por
|
||
`REQUEST_API_ENABLED=true` junto con T08. Requiere JWT válido, propietario y ámbito
|
||
coincidentes, `Idempotency-Key` y un `If-Match` fuerte como `"0"`.
|
||
|
||
```json
|
||
{"event":"SUBMIT","data":{}}
|
||
```
|
||
|
||
El evento y sus datos deben corresponder al flujo publicado de la solicitud.
|
||
No se aceptan estado, roles, identidad, resultados o transición desde el cliente.
|
||
Se aplican los mismos límites de T08: datos canónicos de 256 KiB, cuerpo acotado
|
||
a 256 KiB + 4096 bytes y profundidad JSON 64; rechazo de duplicados y UTF-8 inválido.
|
||
|
||
## Protocolo
|
||
|
||
1. Verificar acceso; bloquear la solicitud con SELECT FOR UPDATE, filtrando otra
|
||
vez propietario/ámbito dentro de la transacción.
|
||
2. Buscar la clave por request_id/idempotency_key. Mismo hash y sujeto autorizado:
|
||
devolver executionId y estado técnico actual. Hash distinto: 409
|
||
IDEMPOTENCY_CONFLICT. El hash SHA-256 incluye evento, datos canónicos y revisión
|
||
esperada; cambiar If-Match también cambia el comando.
|
||
3. Sin replay, comprobar revisión (412) y ausencia de ejecución activa (409
|
||
REQUEST_BUSY). La revisión se comprueba antes de busy, por lo que una carrera
|
||
con dos claves y la misma revisión produce un aceptado y otro 412.
|
||
4. Leer la definición inmutable fijada por flow_id, sin resolver el activo del tipo.
|
||
PUBLISHED y RETIRED pueden ejecutar instancias existentes. Resolver la transición
|
||
para estado/evento, exigir uno de allowedRoles (403), validar inputSchema (422)
|
||
y evaluar guardia pura con request.data/event.data/actor confiables.
|
||
5. Insertar execution PENDING con identidad mínima, evento, transición y estado
|
||
origen. Incrementar revisión y updated_at de solicitud, insertar EVENT_ACCEPTED.
|
||
Confirmar las tres escrituras en una sola transacción READ COMMITTED.
|
||
6. Retornar 202 con Location `/api/v1/executions/{id}` y AcceptedEvent contractual.
|
||
|
||
accepted_revision guarda la revisión **posterior a aceptar** (If-Match + 1), que
|
||
T10 deberá verificar al confirmar trabajo. La solicitud conserva datos y estado
|
||
de negocio; T09 no ejecuta acciones, transiciones finales ni HTTP a proveedores.
|
||
No se guarda el JWT: actor_snapshot contiene subject, businessScope y roles.
|
||
La auditoría registra transición, revisión y correlationId, sin copiar datos del evento.
|
||
|
||
## Reintentos y errores
|
||
|
||
El replay se comprueba antes de revisión, busy, transición, roles y guardia actuales.
|
||
Devuelve el mismo executionId y status actual, incluso después de avanzar la
|
||
solicitud o terminar la ejecución. Exige siempre acceso actual y el sujeto original;
|
||
una revocación del rol de transición no vuelve a autorizar efectos, pues el replay
|
||
solo consulta la aceptación anterior. No incrementa revisión ni duplica auditoría.
|
||
Para reintentar un comando perdido, conservar también el If-Match original.
|
||
|
||
Un evento nuevo usa otra clave. Mientras haya PENDING, RUNNING, RETRY_WAIT o
|
||
RECONCILIATION_REQUIRED no se admite otra ejecución. Las restricciones SQL existentes
|
||
son defensa adicional. Un error de persistencia revierte ejecución, revisión y
|
||
auditoría; no consume la clave.
|
||
|
||
Evento no válido en el estado: 409 INVALID_EVENT. Guardia falsa: 422
|
||
GUARD_NOT_SATISFIED; ruta ausente/tipo incompatible: 422 EVALUATION_ERROR, no una
|
||
condición falsa ni resultado de negocio. Sin If-Match: 428; débil/múltiple/inválido:
|
||
400. Recurso ajeno/inexistente: 404; sin autenticación: 401; infraestructura: 503
|
||
sin exponer SQL. Revisión agotada en Long.MAX_VALUE no se incrementa y rechaza 409.
|
||
|
||
## Alcance y verificación
|
||
|
||
El worker T10 y las integraciones T11 permanecen pendientes. Sin worker, los eventos
|
||
aceptados permanecen PENDING. GET /requests/{id} muestra la revisión nueva y la
|
||
ejecución activa. La URI Location es la contractual; el endpoint GET /executions/{id}
|
||
todavía no está implementado y se completará con el seguimiento de ejecución T10.
|
||
No se afirma idempotencia de efectos externos hasta implementar sus protocolos.
|
||
|
||
EventAcceptanceIT usa PostgreSQL real, login restringido, JWT RSA/JWKS local y HTTP
|
||
real. Reutiliza únicamente el fixture de T07/T08 en orquestador_test. Cubre A07–A09
|
||
en aceptación: replay/409, carreras simultáneas, schemas y guardias, acceso/roles,
|
||
flujo retirado fijado, estados activos y rollback inducido al insertar ejecución,
|
||
actualizar revisión e insertar auditoría. Los cambios a SUCCEEDED/RUNNING/etc. son
|
||
fixtures SQL explícitos de prueba; no simulan un worker terminado en producción.
|
||
Una instancia nueva de adapter recupera el replay desde DB; no se anuncia una prueba
|
||
de reinicio del proceso ni procesamiento externo. T16 verificará el recorrido completo.
|
||
|
||
Comando: `mvnw.cmd clean verify -Pmigration-tests-external` con variables
|
||
MIGRATION_TEST_DB_URL/USER/PASSWORD en entorno. Los esquemas/roles temporales propios
|
||
se eliminan al terminar. No se modifica orquestador ni se despliega el servicio.
|
||
|
||
Desde T10 GET /executions/{id} y worker opcional ya están implementados. La sección
|
||
anterior de alcance corresponde al cierre de T09. Ver WORKER.md: sin WORKER_ENABLED
|
||
los aceptados siguen PENDING; con worker habilitado los flujos sin acciones pueden
|
||
concluir y las integraciones no registradas fallan explícitamente, sin mocks.
|