Per-IP sliding window rate limiter
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

ocaml-rate-limit: enable MDX on lib/rate_limit.mli, harden doc example

The example used handle_request / process_request / respond_429 as
free functions and didn't run anything. Replaced with a toplevel
[Eio_main.run] block that exhausts the limiter (3 allowed, then
rejected) and asserts on the exact decision values, including the
expected retry_after (60.0 - 3.0 = 57.0). The build now catches drift
in the [decision] type and the sliding-window arithmetic.

+15 -6
+4
lib/dune
··· 2 2 (name rate_limit) 3 3 (public_name rate-limit) 4 4 (libraries eio)) 5 + 6 + (mdx 7 + (files rate_limit.mli) 8 + (libraries rate-limit eio eio.unix eio_main))
+11 -6
lib/rate_limit.mli
··· 12 12 {2 Example} 13 13 14 14 {[ 15 - let limiter = Rate_limit.v ~max_requests:100 ~window_seconds:60.0 () 16 - 17 - let handle_request ~ip ~now = 18 - match Rate_limit.check_and_record limiter ~ip ~now with 19 - | Allowed { remaining } -> process_request ~remaining 20 - | Rejected { retry_after } -> respond_429 ~retry_after 15 + let () = 16 + Eio_main.run @@ fun _env -> 17 + let limiter = Rate_limit.v ~max_requests:3 ~window_seconds:60.0 () in 18 + let ip = "10.0.0.1" in 19 + let a1 = Rate_limit.check_and_record limiter ~ip ~now:0.0 in 20 + let _a2 = Rate_limit.check_and_record limiter ~ip ~now:1.0 in 21 + let a3 = Rate_limit.check_and_record limiter ~ip ~now:2.0 in 22 + let rejected = Rate_limit.check_and_record limiter ~ip ~now:3.0 in 23 + assert (a1 = Rate_limit.Allowed { remaining = 2 }); 24 + assert (a3 = Rate_limit.Allowed { remaining = 0 }); 25 + assert (rejected = Rate_limit.Rejected { retry_after = 57.0 }) 21 26 ]} *) 22 27 23 28 type t