Prerequisites. You can read C, understand readiness callbacks and monotonic clocks, and have Linux, a C11 compiler, OpenSSL, the rl-c-client source tree, and libsystemd development files installed.
This example drives a resource rate limit and latency guard with sd-event I/O and timer sources. Protected work executes only when both checks pass, then its measured latency is submitted to the tracker.
This self-contained Linux program uses sd_event_add_io() for each runtime-owned
UDP socket and a one-shot CLOCK_MONOTONIC time source for the current admission
deadline. Read callbacks drain datagrams; timer callbacks advance timeout and
retry state.
The application owns the event sources, request storage, and copied outcome. The runtime owns the client and sockets. Unref I/O and timer sources before runtime destruction closes those sockets.
flowchart TD
Start["Submit resource limit + latency guard"] --> IO["Add sd-event I/O sources"]
IO --> Convert["Convert relative delay into monotonic deadline"]
Convert --> Timer["Arm one-shot time source"]
Timer --> Loop["Run sd_event_loop"]
Loop --> Event{"Which callback ran?"}
Event -->|Socket readable| Read["Drain runtime datagrams"]
Event -->|Timer expired| Timeout["Advance timeout and retry state"]
Read --> Decision{"Admission complete?"}
Timeout --> Decision
Decision -->|No| Convert
Decision -->|Denied| Reject["Skip work and latency report"]
Decision -->|Allowed| Work["Run work, measure it, report one sample"]
Install libsystemd, then build the client library and this folder:
sudo apt-get install libsystemd-dev
make -C ../..
make
export RATELIMITLY_AUTH_KEY=rl-aes1...
./sd-event-example
The equivalent CMake build is:
cmake -S . -B build
cmake --build build
RATELIMITLY_AUTH_KEY=rl-aes1... ./build/sd-event-example
An admitted run exits 0, a policy denial exits 2, and setup or transport failure exits 1.
RATELIMITLY_AUTH_KEY is required. Its encoded key ID defaults production P0
discovery to:
_ratelimitly._udp.c-<key-id>.p0.ratelimitly.com
RATELIMITLY_TENANT optionally overrides that key-derived tenant name. A local
responder can bypass DNS:
export RATELIMITLY_EXAMPLE_SERVER_HOST=127.0.0.1
export RATELIMITLY_EXAMPLE_SERVER_PORT=39082
Set RATELIMITLY_EXAMPLE_SERVER_HOST and RATELIMITLY_EXAMPLE_SERVER_PORT
together, or set neither. One without the other is a configuration error.
Leave both unset for production discovery, and never commit authentication
keys.
The latency guard is the pre-work decision based on samples already stored for
sd-event-protected-service. The post-work latency is a separate value:
r_runtime_admission_run_and_report() measures prepare_response() with a monotonic
clock and submits one new sample to the same tracker.
Resource denial, latency denial, cancellation, transport failure, and failed protected work submit no latency sample.
The client publishes an absolute Unix-epoch deadline. The runtime converts it
to a relative delay; this example adds that delay to sd_event_now() in the
CLOCK_MONOTONIC domain. Wall-clock and monotonic values are never compared
directly. Saturating arithmetic prevents an oversized delay from wrapping.
Re-enable the timer as SD_EVENT_ONESHOT after every timeout transition because
retry processing can change the deadline.
prepare_response() is deliberately short and synchronous. Production handlers
should start nonblocking work only after admission, retain request state, and
measure across asynchronous completion with a monotonic clock. Call
r_client_admission_report_latency() once after successful completion on the
sd-event thread.
If worker threads perform the operation, use an eventfd, pipe, or another
sd-event-compatible notification source to marshal completion back to the loop
before touching the client.
sd-event is part of libsystemd, so this example supports Linux only. Use GLib, libuv, libevent, or native platform loops on macOS and Windows.
Ubuntu 24.04 CI builds and runs this binary against a synthetic responder for allowed, resource-denied, and latency-denied outcomes. Trusted main runs also exercise key-derived production P0 discovery and admission. The per-example P0 lane proves local submission of its fire-and-forget latency report, not server acknowledgement.
| Term | Meaning here |
|---|---|
sd_event_source |
A registered sd-event I/O or timer callback plus its lifetime. |
CLOCK_MONOTONIC |
A clock unaffected by wall-clock corrections, used for elapsed time. |
SD_EVENT_ONESHOT |
A source mode that disables the timer after one callback. |
| GLib | A portable core library whose main loop is an alternative on non-Linux hosts. |
| latency guard | The pre-work policy decision using existing tracker samples. |
| latency sample | The measured duration submitted after admitted work succeeds. |
| CMake | Cross-platform build-system generator provided as an alternative to Make. |