flap documentation

flap fails on a schedule you choose, so you can test how a client behaves when a dependency goes away. Every request carries its own schedule in the query string; the server keeps no state, so every instance gives the same answer for the same parameters and the same instant. This page is generated from the same tables the server validates with.

Failures are periodic. A period contains outages; during an outage the failure endpoints fail, and outside one they answer 200 ok. Add /inspect to a URL to see what the schedule looks like without triggering anything.

Schedule parameters

All failure endpoints and /inspect take these query parameters. Every one is optional. Unknown, repeated and empty parameters are errors, so a typo never falls back to a default.

ParameterKindAccepted valuesDefaultBounds
perioddurationone or more <integer><unit> terms with units ms, s, m, h, d, w (for example 1h30m), or a bare integer meaning seconds1d1s to 366d
outagedurationsame duration syntax as period15m1s to period
countintegernon-negative integer, the number of outages per periodderived from availability0 to 10000, and at most floor(period / outage)
availabilitydecimal percentdecimal percent with up to 4 decimals, for example 99.990 when count is absent0 to 100
seedunsigned 64-bit integerunsigned 64-bit integer00 to 18446744073709551615
placementenumerationeven, scattered or gridevenenumerated; grid needs a period divisible by outage

Give either count or availability, not both: giving both is a 400. With availability the number of outages is derived from it; with count availability follows from the windows. The defaults are a 1 day period, a 15 minute outage, availability 90, even placement and seed 0, which give 10 outages per period and 89.5833 % availability actually achieved.

Placements

The placement parameter decides where the outages sit in a period.

Failure kinds

Three endpoints fail during an outage, each in a different way. All three accept any HTTP method.

KindPathDuring an outageParametersOutside an outage
status/status/{code}Answers the status code from the path (200 to 599) with the text for that code.schedule parameters and retry_after200 ok
hang/hangHolds the response, then answers 200 ok. The hold ends when the outage ends, when duration is up or at the hang cap, whichever comes first, or when the client gives up. Past the concurrent-hang cap it answers 429 at once with an X-Flap-Reason header.schedule parameters and duration200 ok at once
drop/dropSends 200 headers declaring one byte more than it sends, writes bytes body bytes, then resets the TCP connection.schedule parameters and bytes200 ok

Endpoint parameters

These parameters belong to one endpoint, in addition to the schedule parameters.

ParameterEndpointAccepted valuesDefaultBounds
retry_after/status/{code}a whole number of seconds, or "remaining" for the time left in the current outageno Retry-After headerdigits only, 0 to 2147483647
duration/hangsame duration syntax as the schedule parametershold until the outage ends1ms to 366d, and never longer than the hang cap
bytes/dropnon-negative integer, the body bytes sent before the reset0digits only, 0 to the drop-bytes cap
format/inspectjson, html or svg; forces the response format regardless of Acceptchosen from Acceptenumerated
at/inspectan RFC 3339 instant or Unix seconds; evaluates the schedule at that instant instead of nownowyears 1 to 8999

Retry-After

retry_after adds a Retry-After header to /status failures. The header is always a number of seconds. Give a whole number to send it as is, or remaining to send the time left in the current outage, rounded up to whole seconds and never less than 1. Outside an outage no header is sent. When the outage never ends (availability 0) there is no end to point to, so remaining sends no header.

Common rules

Limits

Each instance protects itself with these limits. They are deployment settings, shown here with the values this instance runs.

LimitEnvironment variableValueMeaning
Hang capFLAP_MAX_HANG5mThe longest /hang holds a response, whatever the outage or duration says. Longer values are silently cut to the cap.
Concurrent hangsFLAP_MAX_HANGS256How many /hang responses may be held at once per instance. Beyond that, /hang answers 429 with X-Flap-Reason: too many concurrent hangs.
Drop bytesFLAP_MAX_DROP_BYTES65536The most body bytes /drop writes before the reset. A larger bytes value is a 400.

Inspecting a schedule

/inspect never fails. It takes the schedule parameters and describes the windows that overlap the current period, the state now, the next change and ready-to-call links for the three failure endpoints.

JSON shape

The JSON document is stable. Fields:

FieldTypeMeaning
nowstringThe evaluated instant: the server clock, or the at parameter. RFC 3339, UTC, millisecond precision, like every instant in the document.
schedule.periodstringResolved period in the duration syntax, so it can be fed back as a parameter.
schedule.outagestringResolved outage length in the same syntax.
schedule.countnumberOutages per period, as given or derived from availability.
schedule.availability_targetnumber or nullThe requested availability in percent; null when the schedule was given by count.
schedule.availability_actualnumberThe availability the windows give, in percent, rounded down to four decimals.
schedule.seednumberThe seed. It is an unsigned 64-bit integer, so a JavaScript consumer should read the body as text: numbers above 2^53 lose precision in a double.
schedule.placementstringThe placement.
period.indexnumberNumber of the period containing now, counted from the Unix epoch.
period.startstringStart of that period.
period.endstringEnd of that period.
statestringup or down at now.
next_changestring or nullThe next instant the state flips; null when it never does (no outages, or outages covering the whole period).
windows[].startstringStart of an outage window overlapping the period, ordered by start.
windows[].endstringEnd of the window.
windows[].start_offset_msnumberWindow start minus period start, in milliseconds. Negative for the tail of a window that began in the previous period.
windows[].wrapsbooleanTrue for a window that crosses a period boundary. It is listed in both periods it touches: as its head with a positive offset and as its tail with a negative one.
links.statusstringReady-to-call /status link carrying the same schedule parameters.
links.hangstringReady-to-call /hang link carrying the same schedule parameters.
links.dropstringReady-to-call /drop link carrying the same schedule parameters.

Caveats

Examples

Every example below is run against a test server in the project's test suite, so each behaves as described.

Status failures

A 503 for as long as the outage lasts. availability=0 puts the whole period in outage, so the example always fails.

curl -i 'https://flap.sarak.sh/status/503?availability=0'

Answers 503 with the header X-Flap-State: down.

A 429 with a fixed Retry-After of 120 seconds.

curl -i 'https://flap.sarak.sh/status/429?availability=0&retry_after=120'

Answers 429 with the header Retry-After: 120 and the header X-Flap-State: down.

Retry-After set to the time left in the outage. This one uses the default schedule, so it is a plain 200 whenever no outage is running; a client that obeys the header comes back right as the outage ends.

curl -i 'https://flap.sarak.sh/status/503?retry_after=remaining'

Answers 503 with a Retry-After header and the header X-Flap-State: down.

Any method fails the same way.

curl -i -X POST 'https://flap.sarak.sh/status/500?availability=0'

Answers 500 with the header X-Flap-State: down.

Outside an outage

count=0 means no outages at all, so the endpoint answers 200 ok with the state header.

curl -i 'https://flap.sarak.sh/status/503?count=0'

Answers 200 with the header Cache-Control: no-store, the header X-Flap-State: up and a body containing "ok".

Hangs

Hold the response for 200 ms, then answer 200. Without duration the hold lasts until the outage ends.

curl -i --max-time 30 'https://flap.sarak.sh/hang?availability=0&duration=200ms'

Answers 200 with the header X-Flap-State: down and a body containing "ok". The response is held back first.

Drops

Send the headers and 10 body bytes, then reset the connection.

curl -i --max-time 30 'https://flap.sarak.sh/drop?availability=0&bytes=10'

Answers 200 with the header Content-Length: 11 and the header X-Flap-State: down. The connection is then reset before the declared body is complete, so curl reports an error.

Inspecting a schedule

Ask what the schedule looks like without triggering a failure. /inspect never fails; it describes the state.

curl -s 'https://flap.sarak.sh/inspect?availability=0'

Answers 200 with a body containing "\"state\": \"down\"".

Evaluate the schedule at another instant with at (RFC 3339 or Unix seconds), here with a schedule that has no outages.

curl -s 'https://flap.sarak.sh/inspect?count=0&at=2030-01-01T00:00:00Z'

Answers 200 with a body containing "\"state\": \"up\"".

Spread two 15-minute outages over an hour on a grid, seeded so the layout repeats.

curl -s 'https://flap.sarak.sh/inspect?period=1h&outage=15m&count=2&placement=grid&seed=7'

Answers 200 with a body containing "\"placement\": \"grid\"".

Bad input

A misspelled parameter is an error, never a silent default. The state header is absent because the schedule was never consulted.

curl -i 'https://flap.sarak.sh/status/503?avialability=90'

Answers 400 with a body containing "unknown parameter". No X-Flap-State header is sent.

Ask for JSON errors with the Accept header.

curl -i -H 'Accept: application/json' 'https://flap.sarak.sh/status/99'

Answers 400 with the header Content-Type: application/json and a body containing "{\"error\":".