{"id":16584514,"url":"https://github.com/anmarchenko/gossip-gloomers","last_synced_at":"2026-04-21T06:05:21.478Z","repository":{"id":174218004,"uuid":"634660810","full_name":"anmarchenko/gossip-gloomers","owner":"anmarchenko","description":"my solutions to the gossip gloomers challenge from fly.io","archived":false,"fork":false,"pushed_at":"2023-06-28T12:05:31.000Z","size":11,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-16T15:57:19.482Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anmarchenko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2023-04-30T20:52:31.000Z","updated_at":"2023-05-01T10:20:23.000Z","dependencies_parsed_at":null,"dependency_job_id":"bfb9d211-ff18-4bbe-93fc-68ac7947a3f6","html_url":"https://github.com/anmarchenko/gossip-gloomers","commit_stats":null,"previous_names":["anmarchenko/gossip-gloomers"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anmarchenko%2Fgossip-gloomers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anmarchenko%2Fgossip-gloomers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anmarchenko%2Fgossip-gloomers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anmarchenko%2Fgossip-gloomers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anmarchenko","download_url":"https://codeload.github.com/anmarchenko/gossip-gloomers/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242150810,"owners_count":20080006,"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":[],"created_at":"2024-10-11T22:44:50.496Z","updated_at":"2026-04-21T06:05:21.431Z","avatar_url":"https://github.com/anmarchenko.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Gossip Gloomers\n\n[Gossip Gloomers](https://fly.io/dist-sys/) challenge is a series of distributed systems challenges by Fly.io.\nThis repository contains my solutions to these challenges in Go using [maelstrom-go](https://github.com/jepsen-io/maelstrom/blob/main/demo/go/node.go) library.\nI am doing these challenges to sharpen my Go skills and learn about distributed systems basics.\n\n## Prerequisites\n\n### Go\n\n```bash\nbrew install go\n```\n\n### OpenJDK, graphviz, gnuplot\n\n```bash\nbrew install openjdk graphviz gnuplot\n# add openjdk binaries to PATH\necho 'export PATH=\"/opt/homebrew/opt/openjdk/bin:$PATH\"' \u003e\u003e ~/.zshrc\n```\n\n### Maelstrom\n\nThe solutions are validated using [maelstrom](https://github.com/jepsen-io/maelstrom) workbench.\nDownload [Maelstrom v0.2.3](https://github.com/jepsen-io/maelstrom/releases/tag/v0.2.3) and unpack it to run `maelstrom`\nbinary from the folder directly.\n\n## Challenges\n\n### maelstrom-echo\n\nThis is a warmup [challenge](https://fly.io/dist-sys/1/) where node returns back the same message as it received.\n[Solution](https://github.com/anmarchenko/gossip-gloomers/blob/370f569235aed2b95992185ee9e0bebb07ae1548/maelstrom-echo/main.go) is straightforward: return the same body but replace message type with \"echo_ok\".\n\nRun it:\n\n```bash\ncd maelstrom-echo\ngo install .\n\n# use your maelstrom location\ncd ~/maelstrom\n./maelstrom test -w echo --bin ~/go/bin/maelstrom-echo --node-count 1 --time-limit 10\n```\n\n### maelstrom-unique-ids\n\nIn [this challenge](https://fly.io/dist-sys/2/) you'll need to implement a globally-unique ID generation system.\nIn my [solution](https://github.com/anmarchenko/gossip-gloomers/blob/370f569235aed2b95992185ee9e0bebb07ae1548/maelstrom-unique-ids/main.go) I used [Snowflake ID](https://en.wikipedia.org/wiki/Snowflake_ID) algorithm for ID generation.\n\nSnowflake ID is a 64-bit integer that contains:\n\n- 41 bits for timestamp (in milliseconds since arbitrary chosen epoch)\n- 10 bits for machine id (I used NodeID provided by maelstrom-go library)\n- 12 bits are for machine sequence number to avoid collisions when generating multiple IDs per millisecond\n\nJS pitfall I fell into when solving this challenge: javascript (and thus JSON) decimals are floats and 64 bit integers cannot be represented in JSON precisely. As maelstrom uses JSON as data format, the ID we return must be a string to avoid precision issues\n\nRun it:\n\n```bash\ncd maelstrom-unique-ids\ngo install .\n\n# use your maelstrom location\ncd ~/maelstrom\n./maelstrom test -w unique-ids --bin ~/go/bin/maelstrom-unique-ids --time-limit 30 --rate 1000 --node-count 3 --availability total --nemesis partition\n```\n\n### maelstrom-broadcast\n\n[This challenge](https://fly.io/dist-sys/3a/) is about implementing a broadcast system that gossips messages between all nodes in the cluster.\n\nThe system must handle the following RPC calls:\n\n- **broadcast** - requests that a value be broadcast out to all nodes in the cluster. The node should store the \"message\" value locally so it can be read later\n- **read** - requests that a node return all values that it has seen\n- **topology** - informs the node of who its neighboring nodes are\n\nThere is another RPC call I added in order to gossip messages between nodes:\n\n- **propagate** - requests that a value will be added to a set of messages seen by the node\n\nI implemented a simple [solution](https://github.com/anmarchenko/gossip-gloomers/blob/be07dd76ed4205c30667b27c08bc8ed546f030a9/maelstrom-broadcast/main.go) for this challenge: the messages are being propagated to every node in a cluster once a node receives a new message:\n\n```mermaid\ngraph TB;\n  A(0)--\u003eB(1);\n  A(0)--\u003eC(2);\n  A(0)--\u003eN(N);\n```\n\nThis is not an optimized solution but it solves the problem in this case.\n\nRun it:\n\n```bash\ncd maelstrom-broadcast\ngo install .\n\n# use your maelstrom location\ncd ~/maelstrom\n./maelstrom test -w broadcast --bin ~/go/bin/maelstrom-broadcast --node-count 5 --time-limit 20 --rate 10\n```\n\n### maelstrom-counter\n\n[Grow-only counter](https://fly.io/dist-sys/4/) is a challenge to implement a stateless, grow-only counter which will run against Maelstrom's [g-counter workload](https://github.com/jepsen-io/maelstrom/blob/main/doc/workloads.md#workload-g-counter). In this part the nodes rely on a [sequentially-consistent](https://jepsen.io/consistency/models/sequential) [key/value store service](https://github.com/jepsen-io/maelstrom/blob/main/demo/go/kv.go) provided by Maelstrom.\n\nThe system must support two message types: `add` \u0026 `read`. The system must be eventually consistent and the final read from each node should return the final \u0026 correct count.\n\nMy [solution](https://github.com/anmarchenko/gossip-gloomers/blob/6bf41ab27dbfa57ad8e84f51ee054a40a7b4fb78/maelstrom-counter/main.go) is the following:\n\n- every node has a KV store with the current counter value *per node ID*:  (NodeID -\u003e counter)\n- when `add` message arrives the receiver adds this delta to the counter for its NodeID\n- when `read` message arrives the receiver sums all counter values in its **local** KV store\n- every 5 seconds each node sends `propagate` message to all other nodes with the full contents of its local KV store\n- when `propagate` message arrives the receiver checks the content of message against the local KV store and keeps bigger values for every NodeID\n\nThis way the system becomes eventually consistent: every node tracks the correct counter value for itself independently from others even if network partition happens. As soon as network partition is resolved all the nodes propagate their local state to others so that the final read from each node is correct.\n\nRun it:\n\n```bash\ncd maelstrom-counter\ngo install .\n\n# use your maelstrom location\ncd ~/maelstrom\n./maelstrom test -w g-counter --bin ~/go/bin/maelstrom-counter --node-count 3 --rate 100 --time-limit 20 --nemesis partition\n```\n\n### maelstrom-kafka\n\nWork in progress!\n\nIn this challenge a replicated log service similar to [Kafka](https://kafka.apache.org) is implemented.\n\nRun it:\n\n```bash\ncd maelstrom-kafka\ngo install .\n\n# use your maelstrom location\ncd ~/maelstrom\n./maelstrom test -w kafka --bin ~/go/bin/maelstrom-kafka --node-count 1 --concurrency 2n --time-limit 20 --rate 1000\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanmarchenko%2Fgossip-gloomers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanmarchenko%2Fgossip-gloomers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanmarchenko%2Fgossip-gloomers/lists"}