{"id":28417208,"url":"https://github.com/xpetit/fizzbuzz","last_synced_at":"2025-06-25T23:31:01.478Z","repository":{"id":57651174,"uuid":"447990356","full_name":"xpetit/fizzbuzz","owner":"xpetit","description":"A 500k requests per second fizzbuzz server, using the standard library.","archived":false,"fork":false,"pushed_at":"2023-08-07T13:29:19.000Z","size":171,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-20T21:21:51.969Z","etag":null,"topics":["benchmark","fizzbuzz","fizzbuzz-go","go","golang","performance"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/xpetit/fizzbuzz/v5","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/xpetit.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-01-14T14:11:51.000Z","updated_at":"2024-10-11T04:08:11.000Z","dependencies_parsed_at":"2024-06-20T16:20:21.601Z","dependency_job_id":"2c0b9777-a810-4029-96eb-c89696390c15","html_url":"https://github.com/xpetit/fizzbuzz","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"purl":"pkg:github/xpetit/fizzbuzz","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xpetit%2Ffizzbuzz","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xpetit%2Ffizzbuzz/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xpetit%2Ffizzbuzz/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xpetit%2Ffizzbuzz/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xpetit","download_url":"https://codeload.github.com/xpetit/fizzbuzz/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xpetit%2Ffizzbuzz/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261972560,"owners_count":23238537,"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","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":["benchmark","fizzbuzz","fizzbuzz-go","go","golang","performance"],"created_at":"2025-06-04T04:09:55.374Z","updated_at":"2025-06-25T23:31:01.466Z","avatar_url":"https://github.com/xpetit.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FizzBuzz\n\nFizzBuzz is a Golang HTTP server exposing a RESTful web API that provides a [Fizz buzz](https://en.wikipedia.org/wiki/Fizz_buzz) service.\n\nIt has two endpoints:\n\n- `/api/v2/fizzbuzz`\n  - Accepts five optional query parameters : three integers `int1`, `int2` and `limit`, and two strings `str1` and `str2`.\u003cbr\u003e\n    The default values are: `limit=10`, `int1=2`, `int2=3`, `str1=fizz`, `str2=buzz`.\n  - Returns a list of strings with numbers from 1 to `limit`, where: all multiples of `int1` are replaced by `str1`, all multiples of `int2` are replaced by `str2`, all multiples of `int1` and `int2` are replaced by `str1str2`.\n- `/api/v2/fizzbuzz/stats`\n  - Accept no parameters\n  - Return the parameters corresponding to the most used request, as well as the number of hits for this request\n\nThe server is:\n\n- Ready for production\n- Easy to maintain by other developers\n\n## Usage\n\nRequirements:\n\n- [Go 1.20 or newer](https://golang.org/dl/)\n\nUse this command to directly update and run the service:\n\n```\ngo run github.com/xpetit/fizzbuzz/v5/cmd/fizzbuzzd@latest\n```\n\nTo stop it, type \u003ckbd\u003eCTRL\u003c/kbd\u003e-\u003ckbd\u003eC\u003c/kbd\u003e.\n\nIf you don't trust this program, you can use Docker. Clone this repository and run the following commands inside:\n\n```\ndocker build --tag github.com/xpetit/fizzbuzz/v5 .\ndocker run --rm --publish 8080:8080 github.com/xpetit/fizzbuzz/v5\n```\n\nWhen the service is running, you can query with it with `curl`:\n\n```\ncurl localhost:8080/api/v2/fizzbuzz/stats\n```\n\n\u003e \u003c!-- prettier-ignore --\u003e\n\u003e ```json\n\u003e {\"most_frequent\":{\"count\":0}}\n\u003e ```\n\nUsing the defaults:\n\n```\ncurl localhost:8080/api/v2/fizzbuzz\n```\n\n\u003e \u003c!-- prettier-ignore --\u003e\n\u003e ```json\n\u003e [\"1\",\"fizz\",\"buzz\",\"fizz\",\"5\",\"fizzbuzz\",\"7\",\"fizz\",\"buzz\",\"fizz\"]\n\u003e ```\n\nThe `config` object is now populated:\n\n```\ncurl localhost:8080/api/v2/fizzbuzz/stats\n```\n\n\u003e \u003c!-- prettier-ignore --\u003e\n\u003e ```json\n\u003e {\"most_frequent\":{\"count\":1,\"config\":{\"limit\":10,\"int1\":2,\"int2\":3,\"str1\":\"fizz\",\"str2\":\"buzz\"}}}\n\u003e ```\n\nCustom request:\n\n```\ncurl localhost:8080/api/v2/fizzbuzz -Gdlimit=1 -dint1=1 -dint2=1 -dstr1=buzz -dstr2=lightyear\n```\n\n\u003e ```json\n\u003e [\"buzzlightyear\"]\n\u003e ```\n\n## Design\n\nIn writing this library, several considerations were taken into account:\n\n1. Should it provide a generalized, extensible implementation that supports any number of \"int\" and \"str\"?\n2. Should it provide a FizzBuzz function that not only writes values but returns values?\n   1. Should the returned values be a slice of JSON string or a more compact (binary) representation for later reuse?\n\nThis was discarded for the following reasons:\n\n1. If requirements change, it is easy to adapt the Fizz buzz algorithm because it is simple.\n2. A library that streams JSON strings and one that generates them all at once are a very different story. One cannot be the generalized/abstract version of another.\n\n![relevant XKCD](https://imgs.xkcd.com/comics/the_general_problem.png)\n\n### Packages\n\nThe top-down list of dependencies is as follows:\n\n- `github.com/xpetit/fizzbuzz/v5/cmd/fizzbuzzd`: The main program, running the HTTP server.\n- `github.com/xpetit/fizzbuzz/v5/handlers`: The HTTP handlers.\n- `github.com/xpetit/fizzbuzz/v5/stats`: The statistics services.\n- `github.com/xpetit/fizzbuzz/v5`: The Fizz buzz writer `WriteTo`.\n\n### Performance\n\nBenchmarks performed on an AWS EC2 instance (c6i.4xlarge) with the following specs:\n\n|     |                                        |\n| --- | -------------------------------------- |\n| CPU | Intel Xeon Platinum 8375C CPU @2.90GHz |\n| RAM | 32 GB ECC 2666 MHz                     |\n| Go  | Version 1.20.5                         |\n\nThe programs were compiled with `GOAMD64=v4` and ran with `GOGC=1000` environment variables.\n\n`WriteTo` limits memory allocation, here are the results from 0 to 10 million values of Fizz buzz:\n\n```\nBenchmarkWriteTo/[limit:0e+00]-16   271018197       4.431 ns/op   677.05 MB/s    0 B/op   0 allocs/op\nBenchmarkWriteTo/[limit:1e+00]-16    11806252       99.79 ns/op    60.13 MB/s   32 B/op   5 allocs/op\nBenchmarkWriteTo/[limit:1e+01]-16     5970025       200.2 ns/op   334.67 MB/s   48 B/op   6 allocs/op\nBenchmarkWriteTo/[limit:1e+02]-16     1000000        1016 ns/op   685.71 MB/s   48 B/op   6 allocs/op\nBenchmarkWriteTo/[limit:1e+03]-16      114363       10508 ns/op   694.45 MB/s   48 B/op   6 allocs/op\nBenchmarkWriteTo/[limit:1e+04]-16       10000      106170 ns/op   718.63 MB/s   48 B/op   6 allocs/op\nBenchmarkWriteTo/[limit:1e+05]-16        1074     1113399 ns/op   715.19 MB/s   48 B/op   6 allocs/op\nBenchmarkWriteTo/[limit:1e+06]-16         100    11305590 ns/op   733.82 MB/s   48 B/op   6 allocs/op\nBenchmarkWriteTo/[limit:1e+07]-16           9   117342031 ns/op   735.43 MB/s   49 B/op   6 allocs/op\n```\n\nThe service stops writing values as soon as the API consumer no longer requests them.\n\n[`wrk`](https://github.com/wg/wrk) reports 447k requests/second with a random limit between 1 and 100 (using `-db off` command-line argument):\n\n```\nRunning 10s test @ http://127.0.0.1:8080\n  5 threads and 600 connections\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency     1.45ms    1.85ms  47.51ms   90.65%\n    Req/Sec    90.68k     7.72k  111.89k    68.94%\n  4511934 requests in 10.10s, 1.86GB read\nRequests/sec: 446918.14\nTransfer/sec:    188.49MB\n```\n\nLeaving the database enabled:\n\n```\nRunning 10s test @ http://127.0.0.1:8080\n  4 threads and 400 connections\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency    39.17ms   70.20ms 770.02ms   88.86%\n    Req/Sec     7.81k   636.24    10.35k    76.25%\n  310796 requests in 10.02s, 131.31MB read\nRequests/sec:  31002.22\nTransfer/sec:     13.10MB\n```\n\nAnd with `-db :memory:` command-line argument ([SQLite in-memory DB](https://www.sqlite.org/inmemorydb.html)):\n\n```\nRunning 10s test @ http://127.0.0.1:8080\n  2 threads and 10 connections\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency   242.48us  189.82us   2.21ms   86.00%\n    Req/Sec    22.80k   635.84    24.37k    65.84%\n  458245 requests in 10.10s, 193.35MB read\nRequests/sec:  45371.08\nTransfer/sec:     19.14MB\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxpetit%2Ffizzbuzz","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxpetit%2Ffizzbuzz","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxpetit%2Ffizzbuzz/lists"}