{"id":23141641,"url":"https://github.com/zekrotja/ratelimit","last_synced_at":"2025-08-17T13:31:52.082Z","repository":{"id":62691390,"uuid":"176765641","full_name":"zekroTJA/ratelimit","owner":"zekroTJA","description":"simple token bucket based rate limiter (e.g. for limiting HTTP API requests)","archived":false,"fork":false,"pushed_at":"2022-08-22T11:58:59.000Z","size":27,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-17T11:44:05.234Z","etag":null,"topics":["go","hacktoberfest","library","package","ratelimit","tokenbucket"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zekroTJA.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-03-20T15:39:40.000Z","updated_at":"2023-05-21T11:19:34.000Z","dependencies_parsed_at":"2022-11-04T13:22:19.151Z","dependency_job_id":null,"html_url":"https://github.com/zekroTJA/ratelimit","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/zekroTJA/ratelimit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zekroTJA%2Fratelimit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zekroTJA%2Fratelimit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zekroTJA%2Fratelimit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zekroTJA%2Fratelimit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zekroTJA","download_url":"https://codeload.github.com/zekroTJA/ratelimit/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zekroTJA%2Fratelimit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270856561,"owners_count":24657688,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-17T02:00:09.016Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","hacktoberfest","library","package","ratelimit","tokenbucket"],"created_at":"2024-12-17T14:14:06.209Z","updated_at":"2025-08-17T13:31:51.813Z","avatar_url":"https://github.com/zekroTJA.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n    \u003ch1\u003e~ ratelimit ~\u003c/h1\u003e\n    \u003cstrong\u003eA simple token bucket based rate limiter.\u003c/strong\u003e\u003cbr\u003e\u003cbr\u003e\n    \u003ca href=\"https://godoc.org/github.com/zekroTJA/ratelimit\"\u003e\u003cimg src=\"https://godoc.org/github.com/zekroTJA/ratelimit?status.svg\" /\u003e\u003c/a\u003e\u0026nbsp;\n    \u003ca href=\"https://travis-ci.org/zekroTJA/ratelimit\" \u003e\u003cimg src=\"https://travis-ci.org/zekroTJA/ratelimit.svg?branch=master\" /\u003e\u003c/a\u003e\u0026nbsp;\n    \u003ca href=\"https://coveralls.io/github/zekroTJA/ratelimit\"\u003e\u003cimg src=\"https://coveralls.io/repos/github/zekroTJA/ratelimit/badge.svg\" /\u003e\u003c/a\u003e\u0026nbsp;\n    \u003ca href=\"https://goreportcard.com/report/github.com/zekroTJA/ratelimit\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/zekroTJA/ratelimit\"/\u003e\u003c/a\u003e\n\u003cbr\u003e\n\u003c/div\u003e\n\n---\n\n\u003cdiv align=\"center\"\u003e\n    \u003ccode\u003ego get github.com/zekroTJA/ratelimit\u003c/code\u003e\n\u003c/div\u003e\n\n---\n\n## Intro\n\nThis package provides a verry simple, [token bucket](https://en.wikipedia.org/wiki/Token_bucket) based rate limiter with the ability to return the status of the limiter on reserving a token.\n\n[Here](https://godoc.org/github.com/zekroTJA/ratelimit) you can read the docs of this package, generated by godoc.org.\n\n---\n\n## Usage Example\n\nIn [examples/webserver](examples/webserver) you can find a simple HTTP REST API design limiting accesses with this rate limit package:\n\nTaking a look on just these two functions in [webserver.go](examples/webserver/webserver.go), for example:\n\n```go\n// ...\n\nconst (\n\tlimiterLimit = 10 * time.Second\n\tlimiterBurst = 3\n)\n\n// ...\n\n// checkLimit is a helper function checking\n// the availability of a limiter for the connections\n// address or creating it if not existing. Then,\n// the availability of tokens will be checked\n// to perform an action. This state will be returned\n// as boolean.\nfunc (ws *webServer) checkLimit(w http.ResponseWriter, r *http.Request) bool {\n\t// Getting the address of the incomming connection.\n\t// Because you will likely test this with a local connection,\n\t// the local port number will be attached and differ on every\n\t// request. So, we need to cut away everything behind the last\n\t// \":\", if existent.\n\taddr := r.RemoteAddr\n\tif strings.Contains(addr, \":\") {\n\t\tsplit := strings.Split(addr, \":\")\n\t\taddr = strings.Join(split[0:len(split)-1], \":\")\n\t}\n\n\t// Getting the limiter for the current connections address\n\t// or create one if not existent.\n\tlimiter, ok := ws.limiters[addr]\n\tif !ok {\n\t\tlimiter = ratelimit.NewLimiter(limiterLimit, limiterBurst)\n\t\tws.limiters[addr] = limiter\n\t}\n\n\t// Reserve a token from the limiter.\n\ta, res := limiter.Reserve()\n\n\t// Attach the reservation result to the three headers\n\t// \"X-RateLimit-Limit\"\n\t//    - containing the absolute burst rate\n\t//      of the limiter,\n\t// \"X-RateLimit-Remaining\"\n\t//    - the number of remaining tickets after\n\t//      the request\n\t// \"X-RateLimit-Reset\"\n\t//    - the UnixNano timestamp until a new token\n\t//      will be generated (only if remaining == 0)\n\tw.Header().Set(\"X-RateLimit-Limit\", fmt.Sprintf(\"%d\", res.Burst))\n\tw.Header().Set(\"X-RateLimit-Remaining\", fmt.Sprintf(\"%d\", res.Remaining))\n\tw.Header().Set(\"X-RateLimit-Reset\", fmt.Sprintf(\"%d\", res.Reset.UnixNano()))\n\n\t// Return the succeed status of\n\t// the token request\n\treturn a\n}\n\n// handlerTest is the handler for /api/test root\nfunc (ws *webServer) handlerTest(w http.ResponseWriter, r *http.Request) {\n\t// Check and consume a token from the limiter,\n\t// if available. If succeed, return status 200,\n\t// else status 429.\n\tif ws.checkLimit(w, r) {\n\t\tw.WriteHeader(http.StatusOK)\n\t} else {\n\t\tw.WriteHeader(http.StatusTooManyRequests)\n\t}\n}\n```\n\nOur limiter has a total token volume (= `burst`) of 3 tokens and a limit of 1 token per 10 seconds, which means, that every 10 seconds a new token will be added to the token bucket *(until the bucket has is \"full\")*.\n\nSo, if you send 4 HTTP GET requests in a time span of under 10 Seconds to `/api/test`, you will get following result:\n\n```\n///////////////////////////\n// REQUEST #1\n\n*   Trying 127.0.0.1...\n* TCP_NODELAY set\n* Connected to localhost (127.0.0.1) port 8080 (#0)\n\u003e GET /api/test HTTP/1.1\n\u003e Host: localhost:8080\n\u003e User-Agent: curl/7.61.1\n\u003e Accept: */*\n\u003e\n\u003c HTTP/1.1 200 OK\n\u003c X-Ratelimit-Limit: 3\n\u003c X-Ratelimit-Remaining: 2\n\u003c X-Ratelimit-Reset: 0\n\u003c Date: Thu, 21 Mar 2019 09:03:11 GMT\n\u003c Content-Length: 0\n\u003c\n\n\n///////////////////////////\n// REQUEST #2\n\n*   Trying 127.0.0.1...\n* TCP_NODELAY set\n* Connected to localhost (127.0.0.1) port 8080 (#0)\n\u003e GET /api/test HTTP/1.1\n\u003e Host: localhost:8080\n\u003e User-Agent: curl/7.61.1\n\u003e Accept: */*\n\u003e\n\u003c HTTP/1.1 200 OK\n\u003c X-Ratelimit-Limit: 3\n\u003c X-Ratelimit-Remaining: 1\n\u003c X-Ratelimit-Reset: 0\n\u003c Date: Thu, 21 Mar 2019 09:03:12 GMT\n\u003c Content-Length: 0\n\u003c\n\n\n///////////////////////////\n// REQUEST #3\n\n*   Trying 127.0.0.1...\n* TCP_NODELAY set\n* Connected to localhost (127.0.0.1) port 8080 (#0)\n\u003e GET /api/test HTTP/1.1\n\u003e Host: localhost:8080\n\u003e User-Agent: curl/7.61.1\n\u003e Accept: */*\n\u003e\n\u003c HTTP/1.1 200 OK\n\u003c X-Ratelimit-Limit: 3\n\u003c X-Ratelimit-Remaining: 0\n\u003c X-Ratelimit-Reset: 1553159004253249800\n\u003c Date: Thu, 21 Mar 2019 09:03:14 GMT\n\u003c Content-Length: 0\n\u003c\n\n\n///////////////////////////\n// REQUEST #4\n\n*   Trying 127.0.0.1...\n* TCP_NODELAY set\n* Connected to localhost (127.0.0.1) port 8080 (#0)\n\u003e GET /api/test HTTP/1.1\n\u003e Host: localhost:8080\n\u003e User-Agent: curl/7.61.1\n\u003e Accept: */*\n\u003e\n\u003c HTTP/1.1 429 Too Many Requests\n\u003c X-Ratelimit-Limit: 3\n\u003c X-Ratelimit-Remaining: 0\n\u003c X-Ratelimit-Reset: 1553159004253249800\n\u003c Date: Thu, 21 Mar 2019 09:03:15 GMT\n\u003c Content-Length: 0\n\u003c\n```\n\nAs you can see, we are receiving status code `200 OK` exactly 3 times. Also, you can see that the ammount of remaining tokens is returned in a `X-Ratelimit-Remaining` header and also the time until a new token will be generated in the `X-Ratelimit-Reset` header *(as UnixNano timestamp)* when no tokens are remaining. \n\nThis concept ofreturning these information as headers were inspired by the design of the [REST API of discordapp.com](https://discordapp.com/developers/docs/topics/rate-limits).\n\n---\n\nCopyright (c) 2019 zekro Development (Ringo Hoffmann).  \nCovered by MIT licence.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzekrotja%2Fratelimit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzekrotja%2Fratelimit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzekrotja%2Fratelimit/lists"}