Zwing Docs

Ingress — async and sync

POST /ingress vs POST /ingress/sync, auth, throttling, queue dispatch, and egress sync client

Base URL and routes

Ingress is served with globalPrefix: /ingress (port 3001 in dev). Effective routes:

MethodPathGuards
POST/ingressAuthGuard
POST/ingress/syncAuthGuard, EnterpriseSyncThrottleGuard
GET/ingress/health(health controller)

Controllers live in apps/ingress-service/src/controller/ingress.ts. The body type is Record<string, any> (validated downstream by business rules, not a single DTO class).

Async: POST /ingress

IngressService.receiveRequest:

  1. loadInboundContext — Persists the raw JSON body to blob storage (DipV2Storage), creates an event log in pending, resolves app and events for ctx.appId + ssoEnterpriseId.
  2. Calls requestHandler.handleRequest with void (not awaited) so the HTTP response returns immediately.
  3. Returns { ackId, message } where ackId is the event log id.

So the client gets an acknowledgement while processing continues in the background.

Inside RequestHandler (async path, skipQueue false):

  • Resolves connector–event mappings for the outbound event; may block the log if none exist or connectors are missing.
  • Creates jobs and dip job tasks (cloning the event task tree into runtime tasks).
  • For each pending job, Dispatch publishes to the Intent queue with job name
    dip.v2.{ssoEnterpriseId}_{baCode}.regular or .priority depending on whether the mapping is marked priority.
  • Updates the event log to jobs-created with connector ids.

Sync: POST /ingress/sync

receiveRequestSync awaits the same loadInboundContext, then handleRequest(..., { skipQueue: true }).

Sync-only rules enforced in request-handler.ts:

  • At most one connector–event mapping for the outbound event; otherwise the log is blocked and a structured error is returned.
  • With exactly one mapping, tasks must satisfy validateLinearTaskChainForSync (single root, no branching) or sync fails with Sync API can't be used where task structure is not linear.
  • No Dispatch — jobs stay queued for inline execution.

If processing succeeds and there are no jobs, the API returns a no-jobs shaped payload via SyncApiResponseTransformer.

If there are jobs, EgressSyncClient.executeJobs(pendingJobIds) runs:

  • URL: {baseUrl}/egress/internal/sync/execute where baseUrl is the egress service root (no /egress segment); see buildEgressSyncExecuteUrl in egress-sync-client.ts.
  • Config: services.gip.baseUrl (default http://127.0.0.1:3002), services.gip.timeoutMs (default 300000 ms).
  • On axios timeout, EgressSyncTimeoutError is caught and the client receives a timeout-shaped sync response (event log recorded; async processing may still complete).

Sequence

sequenceDiagram
  participant Client
  participant Ingress
  participant Storage
  participant Mongo
  participant Kafka
  participant Egress
  Client->>Ingress: POST /ingress or /ingress/sync
  Ingress->>Storage: persist raw payload
  Ingress->>Mongo: event log, jobs, job tasks
  alt async
    Ingress->>Kafka: Dispatch dip.v2.enterprise_ba.regular or .priority
    Ingress-->>Client: ackId
    Kafka->>Egress: consumer
    Egress->>Mongo: execute job tasks
  else sync
    Ingress->>Egress: POST .../egress/internal/sync/execute
    Egress->>Mongo: executeJob inline
    Egress-->>Ingress: job summaries
    Ingress-->>Client: sync payload
  end

Other ingress behaviour

  • refDocNo: Extracted from the payload using event.refDocPath; if missing, sync returns a clear error (Ref doc no not found).
  • Sequential mappings (isSequential + sequentialKey): May set job status blocked or interact with job sync checkpoints before dispatch.
Edit on GitHub