this repo has no description

Compare changes

Choose any two refs to compare.

Changed files
+193 -12
+177
README.md
··· 1 + # swim 2 + 3 + An OCaml 5 implementation of the SWIM (Scalable Weakly-consistent Infection-style Process Group Membership) protocol for cluster membership and failure detection. 4 + 5 + ## Overview 6 + 7 + This library provides: 8 + 9 + - **Membership Management**: Automatic discovery and tracking of cluster nodes 10 + - **Failure Detection**: Identifies unreachable nodes using periodic probes and indirect checks 11 + - **Gossip Protocol**: Propagates state changes (Alive/Suspect/Dead) across the cluster 12 + - **Messaging**: Cluster-wide broadcast (gossip-based) and direct point-to-point UDP messaging 13 + - **Encryption**: Optional AES-256-GCM encryption for all network traffic 14 + 15 + Built on [Eio](https://github.com/ocaml-multicore/eio) for effect-based concurrency and [Kcas](https://github.com/ocaml-multicore/kcas) for lock-free shared state. 16 + 17 + ## Requirements 18 + 19 + - OCaml >= 5.1 20 + - Dune >= 3.20 21 + 22 + ## Installation 23 + 24 + ```bash 25 + opam install . 26 + ``` 27 + 28 + Or add to your dune-project: 29 + 30 + ``` 31 + (depends (swim (>= 0.1.0))) 32 + ``` 33 + 34 + ## Usage 35 + 36 + ### Basic Example 37 + 38 + ```ocaml 39 + open Swim.Types 40 + 41 + let config = { 42 + default_config with 43 + bind_port = 7946; 44 + node_name = Some "node-1"; 45 + secret_key = "your-32-byte-secret-key-here!!!"; (* 32 bytes for AES-256 *) 46 + encryption_enabled = true; 47 + } 48 + 49 + let () = 50 + Eio_main.run @@ fun env -> 51 + Eio.Switch.run @@ fun sw -> 52 + let env_wrap = { stdenv = env; sw } in 53 + match Swim.Cluster.create ~sw ~env:env_wrap ~config with 54 + | Error `Invalid_key -> failwith "Invalid secret key" 55 + | Ok cluster -> 56 + Swim.Cluster.start cluster; 57 + 58 + (* Join an existing cluster *) 59 + let seed_nodes = ["192.168.1.10:7946"] in 60 + (match Swim.Cluster.join cluster ~seed_nodes with 61 + | Ok () -> Printf.printf "Joined cluster\n" 62 + | Error `No_seeds_reachable -> Printf.printf "Failed to join\n"); 63 + 64 + (* Send a broadcast message to all nodes *) 65 + Swim.Cluster.broadcast cluster ~topic:"config" ~payload:"v2"; 66 + 67 + (* Send a direct message to a specific node *) 68 + let target = node_id_of_string "node-2" in 69 + Swim.Cluster.send cluster ~target ~topic:"ping" ~payload:"hello"; 70 + 71 + (* Handle incoming messages *) 72 + Swim.Cluster.on_message cluster (fun sender topic payload -> 73 + Printf.printf "From %s: [%s] %s\n" 74 + (node_id_to_string sender.id) topic payload); 75 + 76 + (* Listen for membership events *) 77 + Eio.Fiber.fork ~sw (fun () -> 78 + let stream = Swim.Cluster.events cluster in 79 + while true do 80 + match Eio.Stream.take stream with 81 + | Join node -> Printf.printf "Joined: %s\n" (node_id_to_string node.id) 82 + | Leave node -> Printf.printf "Left: %s\n" (node_id_to_string node.id) 83 + | Suspect_event node -> Printf.printf "Suspect: %s\n" (node_id_to_string node.id) 84 + | Alive_event node -> Printf.printf "Alive: %s\n" (node_id_to_string node.id) 85 + | Update _ -> () 86 + done); 87 + 88 + Eio.Fiber.await_cancel () 89 + ``` 90 + 91 + ### Configuration Options 92 + 93 + | Field | Default | Description | 94 + |-------|---------|-------------| 95 + | `bind_addr` | "0.0.0.0" | Interface to bind listeners | 96 + | `bind_port` | 7946 | Port for SWIM protocol | 97 + | `protocol_interval` | 1.0 | Seconds between probe rounds | 98 + | `probe_timeout` | 0.5 | Seconds to wait for Ack | 99 + | `indirect_checks` | 3 | Peers to ask for indirect probes | 100 + | `secret_key` | (zeros) | 32-byte key for AES-256-GCM | 101 + | `encryption_enabled` | false | Enable encryption | 102 + 103 + ## Interoperability Testing 104 + 105 + The library includes interoperability tests with HashiCorp's [memberlist](https://github.com/hashicorp/memberlist) (Go). This verifies protocol compatibility with the reference implementation. 106 + 107 + ### Prerequisites 108 + 109 + - Go >= 1.19 110 + - OCaml environment with dune 111 + 112 + ### Running Interop Tests 113 + 114 + The interop test suite starts a Go memberlist node and an OCaml node, then verifies they can discover each other and exchange messages. 115 + 116 + ```bash 117 + # Build the OCaml project 118 + dune build 119 + 120 + # Build the Go memberlist server 121 + cd interop && go build -o memberlist-server main.go && cd .. 122 + 123 + # Run the interop test 124 + bash test/scripts/test_interop.sh 125 + 126 + # Run with encryption enabled 127 + bash test/scripts/test_interop_encrypted.sh 128 + ``` 129 + 130 + ### Manual Interop Testing 131 + 132 + Start the Go node: 133 + 134 + ```bash 135 + cd interop 136 + go run main.go -name go-node -bind 127.0.0.1 -port 7946 137 + ``` 138 + 139 + In another terminal, start the OCaml node: 140 + 141 + ```bash 142 + dune exec swim-interop-test 143 + ``` 144 + 145 + The OCaml node will connect to the Go node and print membership statistics for 30 seconds. 146 + 147 + ### Available Test Scripts 148 + 149 + | Script | Description | 150 + |--------|-------------| 151 + | `test/scripts/test_interop.sh` | Basic interop test | 152 + | `test/scripts/test_interop_encrypted.sh` | Interop with AES encryption | 153 + | `test/scripts/test_interop_udp_only.sh` | UDP-only communication test | 154 + | `test/scripts/test_interop_go_joins.sh` | Go node joining OCaml cluster | 155 + 156 + ### Debug Utilities 157 + 158 + ```bash 159 + # Test packet encoding/decoding 160 + dune exec swim-debug-codec 161 + 162 + # Receive and display incoming SWIM packets 163 + dune exec swim-debug-recv 164 + 165 + # Send manual ping to a target node 166 + dune exec swim-debug-ping 167 + ``` 168 + 169 + ## Running Tests 170 + 171 + ```bash 172 + dune runtest 173 + ``` 174 + 175 + ## License 176 + 177 + ISC License. See [LICENSE](LICENSE) for details.
+8 -5
dune-project
··· 1 1 (lang dune 3.20) 2 2 3 3 (name swim) 4 + (version 0.1.0) 4 5 5 6 (generate_opam_files true) 6 7 7 8 (source 8 - (github gdiazlo/swim)) 9 + (uri git+https://tangled.org/gdiazlo.tngl.sh/swim)) 9 10 10 - (authors "Guillermo Diaz-Romero <guillermo.diaz@gmail.com>") 11 + (authors "Gabriel Diaz") 11 12 12 - (maintainers "Guillermo Diaz-Romero <guillermo.diaz@gmail.com>") 13 + (maintainers "Gabriel Diaz") 13 14 14 - (license MIT) 15 + (license ISC) 15 16 16 - (documentation https://github.com/gdiazlo/swim) 17 + (homepage https://tangled.org/gdiazlo.tngl.sh/swim) 18 + (bug_reports https://tangled.org/gdiazlo.tngl.sh/swim/issues) 19 + (documentation https://tangled.org/gdiazlo.tngl.sh/swim) 17 20 18 21 (package 19 22 (name swim)
+8 -7
swim.opam
··· 1 1 # This file is generated by dune, edit dune-project instead 2 2 opam-version: "2.0" 3 + version: "0.1.0" 3 4 synopsis: 4 5 "SWIM protocol library for cluster membership and failure detection" 5 6 description: 6 7 "Production-ready SWIM (Scalable Weakly-consistent Infection-style Process Group Membership) protocol library in OCaml 5 for cluster membership, failure detection, and lightweight pub/sub messaging. Features lock-free coordination via kcas, zero-copy buffer management, and AES-256-GCM encryption." 7 - maintainer: ["Guillermo Diaz-Romero <guillermo.diaz@gmail.com>"] 8 - authors: ["Guillermo Diaz-Romero <guillermo.diaz@gmail.com>"] 9 - license: "MIT" 8 + maintainer: ["Gabriel Diaz"] 9 + authors: ["Gabriel Diaz"] 10 + license: "ISC" 10 11 tags: [ 11 12 "swim" "cluster" "membership" "gossip" "failure detection" "ocaml5" "eio" 12 13 ] 13 - homepage: "https://github.com/gdiazlo/swim" 14 - doc: "https://github.com/gdiazlo/swim" 15 - bug-reports: "https://github.com/gdiazlo/swim/issues" 14 + homepage: "https://tangled.org/gdiazlo.tngl.sh/swim" 15 + doc: "https://tangled.org/gdiazlo.tngl.sh/swim" 16 + bug-reports: "https://tangled.org/gdiazlo.tngl.sh/swim/issues" 16 17 depends: [ 17 18 "ocaml" {>= "5.1"} 18 19 "dune" {>= "3.20" & >= "3.20"} ··· 46 47 "@doc" {with-doc} 47 48 ] 48 49 ] 49 - dev-repo: "git+https://github.com/gdiazlo/swim.git" 50 + dev-repo: "git+https://tangled.org/gdiazlo.tngl.sh/swim" 50 51 x-maintenance-intent: ["(latest)"]