I built a GCRA-based Rate Limiter in Zig

https://github.com/minhqdao/zimit

Hey there :waving_hand:t4:

I’ve been wanting to build something in Zig for a while and now I finished my rate limiter. :slight_smile:

It implements the GCRA (Generic Cell Rate Algorithm) with a token-bucket-like API (which is more intuitive/user-friendly) and it is compatible with Zig 0.16.0. It supports per-key rate limiting (e.g. per IP address or user ID) and global limiting (e.g. if you want to protect your resource).

You can use it like this:

const std = @import("std");
const zimit = @import("zimit");

pub fn main(init: std.process.Init) !void {
    const io = init.io;

    var sys = zimit.SystemClock.init(io);

    var limiter = try zimit.GlobalLimiter.init(.{
        .rate = 100,
        .per = .second,
        .burst = 20,
        .clock = sys.clock(),
    });

    switch (limiter.allow()) {
        .allowed => std.debug.print("allowed\n", .{}),
        .denied => |d| {
            std.debug.print("denied, time until allowed: {d}ms\n", .{d.retry_after_ms_ceil()});
        },
    }
}

GlobalLimiter is thread-safe, RateLimiter is not because it uses a hash map. So make sure to wrap it with a std.Io.Mutex when using it in a multi-threading environment.

Feel free to try it out, let me know if there is anything I can improve and I’m happy to work on it. :handshake:

4 Likes