Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ AAAS_ADMIN_ENAMES=""
# Secret used to sign AaaS portal session JWTs
AAAS_JWT_SECRET="replace-with-a-strong-secret"
# Webhook delivery tuning
AWARENESS_MAX_ATTEMPTS=8
AWARENESS_MAX_ATTEMPTS=3
AWARENESS_DELIVERY_POLL_MS=2000
# The one-time Neo4j backfill reuses the standard NEO4J_URI / NEO4J_USER /
# NEO4J_PASSWORD vars at the top of this file - it reads evault-core's graph
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/Services/Awareness-as-a-Service.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ AaaS is designed to be dropped in with **zero receiver-side changes**:
| `AWARENESS_SERVICE_URL` | (evault-core) where to POST packets |
| `AAAS_ADMIN_ENAMES` | Comma-separated admin eNames |
| `AAAS_JWT_SECRET` | Signs portal session JWTs |
| `AWARENESS_MAX_ATTEMPTS` | Delivery attempts before dead-lettering (default 8) |
| `AWARENESS_MAX_ATTEMPTS` | Delivery attempts before dead-lettering (default 3) |
| `AWARENESS_DELIVERY_POLL_MS` | Delivery engine poll interval (default 2000) |
| `NEO4J_URI` / `NEO4J_USER` / `NEO4J_PASSWORD` | Standard eVault Neo4j vars — reused by the one-time backfill |
| `PUBLIC_AWARENESS_API_URL` | (portal) AaaS API base URL |
Expand Down
2 changes: 1 addition & 1 deletion services/awareness-service/api/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const config = {
.filter(Boolean),
/** Secret used to sign portal session JWTs. */
jwtSecret: process.env.AAAS_JWT_SECRET ?? "awareness-dev-secret",
maxAttempts: parseInt(process.env.AWARENESS_MAX_ATTEMPTS ?? "8", 10),
maxAttempts: parseInt(process.env.AWARENESS_MAX_ATTEMPTS ?? "3", 10),
deliveryPollMs: parseInt(
process.env.AWARENESS_DELIVERY_POLL_MS ?? "2000",
10,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export type DeliveryStatus =
| "pending"
| "delivering"
| "delivered"
| "failed";
| "failed"
| "dead";

/**
* A queued webhook delivery of one packet to one subscription. The unique
Expand Down
8 changes: 7 additions & 1 deletion services/awareness-service/api/src/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,13 @@ export const openApiDocument = {
packetId: { type: "string" },
status: {
type: "string",
enum: ["pending", "delivering", "delivered", "failed"],
enum: [
"pending",
"delivering",
"delivered",
"failed",
"dead",
],
},
attempts: { type: "integer" },
nextAttemptAt: { type: "string", format: "date-time" },
Expand Down
11 changes: 9 additions & 2 deletions services/awareness-service/api/src/services/DeliveryEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,19 @@ export class DeliveryEngine {
.update(Delivery)
.set({ status: "delivering" })
.where(
// Only pending/failed deliveries still under the attempt
// limit are claimable. `dead` deliveries (and any that
// already hit the cap) are terminal and never re-claimed.
`id IN (
SELECT id FROM deliveries
WHERE status IN ('pending', 'failed')
AND attempts < :maxAttempts
AND "nextAttemptAt" <= now()
ORDER BY "nextAttemptAt"
LIMIT :limit
FOR UPDATE SKIP LOCKED
)`,
{ limit: BATCH_SIZE },
{ limit: BATCH_SIZE, maxAttempts: config.maxAttempts },
)
.returning("*")
.execute();
Expand Down Expand Up @@ -181,8 +185,11 @@ export class DeliveryEngine {
const deliveryRepo = AppDataSource.getRepository(Delivery);

if (attempts >= config.maxAttempts) {
// Terminal: mark `dead` so the engine never re-claims it. (Using
// `failed` here let exhausted deliveries be picked up again every
// tick, inflating attempts and spawning duplicate dead letters.)
await deliveryRepo.update(delivery.id, {
status: "failed",
status: "dead",
attempts,
lastError: message,
lastResponseStatus: responseStatus,
Expand Down
Loading