- Reference
- Test sinks
Reference
Test sinks
A receiver in a project's test environment that fails on demand, for rehearsing delivery failures before your own receiver meets them.
A test sink is a receiver Greatwait runs for you, in a project’s test
environment, that fails on demand. Give it a program — fail twice and then
succeed, hold the connection until the sender gives up, answer 429 with a
delay hint — point a destination at it, and watch what the sender
concludes from each failure before your own receiver ever produces one.
No quickstart uses one. First value is a delivery to a receiver you own, in the live environment the dashboard opens. A sink exists only in the test environment, refuses a live credential, and never sends a delivery anywhere.
Reach the test environment
The dashboard does not link to the test environment. Its address works:
- Sign in and open your project. The address ends in
/live, as inhttps://app.greatwait.dev/o/<organization>/p/<project>/live. - Change
livetotestand open that address. The workspace’s System page reads Environment: test. - Open
/o/<organization>/p/<project>/test/settings/access, choose New key, and copy the secret it shows once. That credential acts in the test environment and nowhere else.
Keep it apart from the key the quickstarts export as GREATWAIT_API_KEY.
Sink operations refuse a live credential, and a live credential is what
those pages use.
Rehearse a failure
- Create a destination with
endpoints.create. Its address has to pass the same public HTTPS check as any destination; step 3 replaces it. Give it anamewhen an active destination already delivers to that address, or the call answersstate_conflict. - Create a sink for that destination with
testsinks.createand a program. The response carries the sink’surl. - Point the destination at that
urlwithendpoints.update. - Create a one-shot against the destination with
schedules.create. - Read what the sink received with
sinkdeliveries.list, and what the sender concluded withattempts.list.
A program that fails twice and then succeeds:
{
"behavior": "server_error",
"forDeliveries": 2,
"then": "success"
}
forDeliveries is how many deliveries the behavior applies to, and then
is what the sink does after them; then needs forDeliveries. status
chooses the answer for client_error or server_error, delayMs sets how
long delay waits, retryAfterSeconds sets the hint rate_limited sends,
and completionDelayMs sets how long a deferring behavior waits before it
reports.
Behaviors
| Behavior | What the sink does | The sender, at the default status |
|---|---|---|
client_error | Answers a selected 4xx. The sender records a customer refusal, and retries it only when the status is one the receiver may recover from — 401, 403 and 404, listed as clientErrorStatusesRetried. The default, 422, is not one of those, so it settles on the first attempt. | stops: the refusal is final |
defer_abandon | Acknowledges the delivery and then never reports at all. The sender waits until the deadline in the envelope and records ambiguity, because a receiver that took the work and went quiet may well have done it. This is the case the completion deadline exists to bound. | ambiguous: it may have run |
defer_fail | Acknowledges the delivery, then reports failed with the credential in its signed envelope. The occurrence goes back on the ordinary retry ladder — the same place a 500 puts it — which is how a receiver says its job died rather than that it vanished. | retries it |
defer_succeed | Acknowledges the delivery with 202 and the pending marker, keeps the work, then reports succeeded with the credential in its signed envelope. The whole deferred exchange, without writing a receiver. | records success |
delay | Waits a bounded interval, then accepts. Exercises a slow receiver that still succeeds. | records success |
disconnect | Authenticates the delivery and then drops the connection without processing it, holding until the sender gives up. Nothing was claimed and nothing ran, but the sender cannot know that. | ambiguous: it may have run |
duplicate | Accepts and reports the occurrence as already handled, without processing it again. What occurrence idempotency looks like from the sender’s side. | records success |
invalid_signature | Rejects the delivery as unauthenticated regardless of whether the signature verified. Exercises the key-mismatch path without forging a signature. The sender retries on the receiver’s ordinary budget, because the usual cause is a credential the receiver is about to redeploy. | retries it |
rate_limited | Answers 429 with a bounded Retry-After. The sender honours the hint and does not spend its give-up budget. | retries it |
server_error | Answers a selected 5xx. The sender retries with backoff. | retries it |
success | Verifies, records, and accepts. | records success |
timeout | Verifies and records the delivery, then never answers. The receiver acted and the sender cannot know it. | ambiguous: it may have run |
A request that fails verification is refused whatever the program says;
invalid_signature is how to rehearse a key mismatch without forging
anything.
Bounds
| What | Bound |
|---|---|
| Sinks per project environment | 10 |
Longest delay | 10,000 ms |
Longest a timeout or disconnect holds the request | 45,000 ms |
| Longest wait before a deferred report | 5,000 ms |
| Delivery receipts kept per sink, oldest evicted first | 50 |
| Largest request body a sink reads | 69,632 bytes |
| Body bytes kept on a receipt | 4,096 bytes |
Operations
| Operation | Request | Scopes |
|---|---|---|
testsinks.create | POST /v1/test-sinks | endpoints:write |
testsinks.list | GET /v1/test-sinks | endpoints:read |
testsinks.read | GET /v1/test-sinks/{sinkId} | endpoints:read |
testsinks.delete | DELETE /v1/test-sinks/{sinkId} | endpoints:write |
testsinks.configure | PUT /v1/test-sinks/{sinkId}/program | endpoints:write |
sinkdeliveries.list | GET /v1/test-sinks/{sinkId}/deliveries | endpoints:read |
sinkdeliveries.read | GET /v1/test-sinks/{sinkId}/deliveries/{deliveryRecordId} | endpoints:read |