Skip to content

Commit 641ecda

Browse files
add docs
1 parent 00487c4 commit 641ecda

File tree

3 files changed

+335
-25
lines changed

3 files changed

+335
-25
lines changed

README.md

Lines changed: 248 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,240 @@
1-
# barnacle
1+
# Barnacle
22

33
[![Package Version](https://img.shields.io/hexpm/v/barnacle)](https://hex.pm/packages/barnacle)
44
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/barnacle/)
55

6+
Self-healing clusters for Gleam applications on the BEAM!
7+
8+
Connect to other BEAM nodes, and automatically reconnect when they go down.
9+
10+
## Features
11+
12+
- Discover nodes using different strategies. Built-in strategies:
13+
- Local EPMD
14+
- Remote EPMD
15+
- DNS
16+
- Automatically reconnect to nodes when they come back online
17+
- Supply your own strategies
18+
- Listen to events
19+
- Trigger refreshes manually
20+
21+
## Getting Started
22+
23+
```sh
24+
gleam add barnacle
25+
```
26+
27+
You'll also need to start your Gleam process with a node name, and set the cookie.
28+
You can do this using the `ERL_FLAGS` environment variable.
29+
30+
> [!NOTE]
31+
> There's a Fly.io example coming soon.
32+
633
```sh
7-
gleam add barnacle@1
34+
ERL_FLAGS="-name my_app@127.0.0.1 -setcookie my_cookie" gleam run
35+
```
36+
37+
### Start Barnacle under a Supervisor (recommended)
38+
39+
```gleam
40+
import barnacle
41+
import gleam/erlang/process
42+
import gleam/otp/supervisor
43+
44+
pub fn main() {
45+
// Configure your Barnacle
46+
let barnacle =
47+
barnacle.local_epmd()
48+
|> barnacle.with_poll_interval(15_000)
49+
|> barnacle.with_name("my_barnacle")
50+
51+
// Create a process to receive the child process later
52+
let self = process.new_subject()
53+
54+
// Start the child process under a supervisor
55+
let barnacle_worker = barnacle.child_spec(barnacle, None)
56+
let assert Ok(_) = supervisor.start(supervisor.add(_, barnacle_worker))
57+
58+
// Get a subject to send messages to the child process
59+
let assert Ok(barnacle_subject) = process.receive(self, 10_000)
60+
61+
// Continue your setup...
62+
63+
process.sleep_forever()
64+
}
65+
```
66+
67+
### Start Barnacle as a standalone actor
68+
69+
This is **not** recommended as your barnacle won't be restarted if it crashes for any
70+
reason.
71+
72+
```gleam
73+
import barnacle
74+
import gleam/erlang/process
75+
76+
pub fn main() {
77+
// Configure your Barnacle
78+
let barnacle =
79+
barnacle.local_epmd()
80+
|> barnacle.with_poll_interval(15_000)
81+
|> barnacle.with_name("my_barnacle")
82+
83+
// Start the actor
84+
let barnacle_subject = barnacle.start(barnacle)
85+
86+
// Continue your setup...
87+
88+
process.sleep_forever()
89+
}
90+
```
91+
92+
## Strategies
93+
94+
Barnacle ships with a few built-in strategies, but you can also supply your own by
95+
providing a single callback function.
96+
97+
### Local EPMD
98+
99+
Discover nodes using the local EPMD. This will automatically attempt to connect to
100+
nodes that are running on the same machine.
101+
102+
```gleam
103+
import barnacle
104+
105+
pub fn main() {
106+
barnacle.local_epmd()
107+
|> barnacle.start
108+
}
109+
```
110+
111+
### Remote EPMD
112+
113+
Connect to nodes using a known list.
114+
115+
```gleam
116+
import barnacle
117+
import gleam/erlang/atom
118+
119+
pub fn main() {
120+
barnacle.epmd(
121+
["node1@192.168.1.1", "node2@192.168.1.2"]
122+
|> list.map(atom.create_from_string),
123+
)
124+
|> barnacle.start
125+
}
126+
```
127+
128+
### DNS
129+
130+
Discover nodes using DNS.
131+
132+
The first argument is the basename of the node. Currently, Barnacle only supports
133+
connecting to nodes with the same basename.
134+
135+
Barnacle provides a helper function to get the basename of the current node.
136+
137+
```gleam
138+
import barnacle
139+
140+
pub fn main() {
141+
let assert Ok(basename) = barnacle.get_node_basename(node.self())
142+
barnacle.dns(
143+
basename,
144+
// The hostname to query against
145+
"my_app.example.com",
146+
)
147+
|> barnacle.start
148+
}
149+
```
150+
151+
### Creating a custom strategy
152+
153+
You can create your own strategy using the `new_strategy` function.
154+
155+
```gleam
156+
import barnacle
157+
158+
pub fn main() {
159+
barnacle.new_strategy(
160+
// Discover nodes
161+
fn() {
162+
Ok([])
163+
},
164+
)
165+
|> barnacle.custom
166+
|> barnacle.start
167+
}
168+
```
169+
170+
You can also supply your own functions for connecting, disconnecting, and listing nodes.
171+
If these are not supplied, the built-in functions will be used.
172+
173+
This may be useful if you want to use an alternative to Distributed Erlang, such as
174+
[Partisan](https://github.com/lasp-lang/partisan).
175+
176+
```gleam
177+
import barnacle
178+
179+
pub fn main() {
180+
barnacle.new_strategy(my_discover_function)
181+
|> barnacle.with_connect_nodes_function(my_connect_function)
182+
|> barnacle.with_disconnect_nodes_function(my_disconnect_function)
183+
|> barnacle.with_list_nodes_function(my_list_function)
184+
|> barnacle.custom
185+
|> barnacle.start
186+
}
8187
```
188+
189+
You can find more information about creating custom strategies in the
190+
[docs](/barnacle/barnacle.html#custom).
191+
192+
## Events
193+
194+
You can provide a custom subject to receive events from your barnacle.
195+
This will be notified whenever the barnacle refreshes, is paused, or is shutdown.
196+
9197
```gleam
10198
import barnacle
199+
import gleam/erlang/process
11200
12201
pub fn main() {
13-
// TODO: An example of the project in use
202+
let self = process.new_subject()
203+
204+
// Configure your Barnacle
205+
let barnacle =
206+
barnacle.local_epmd()
207+
|> barnacle.with_poll_interval(15_000)
208+
|> barnacle.with_name("my_barnacle")
209+
|> barnacle.with_listener(self)
210+
211+
// Start the actor
212+
barnacle.start(barnacle)
213+
214+
// Wait for the barnacle to refresh
215+
process.sleep(10_000)
216+
let assert Ok(barnacle.RefreshResponse(Ok(new_nodes))) = process.receive(self, 10_000)
217+
}
218+
```
219+
220+
## Manual interactions
221+
222+
You can interact with your barnacle manually by sending messages to it.
223+
224+
```gleam
225+
import barnacle
226+
import gleam/erlang/process
227+
import gleam/otp/actor
228+
229+
pub fn main() {
230+
// Start a barnacle
231+
let barnacle_subject =
232+
barnacle.local_epmd()
233+
|> barnacle.start
234+
235+
let assert Ok(_) = barnacle.pause(barnacle_subject, 1000)
236+
let assert Ok(_) = barnacle.refresh(barnacle_subject, 10_000)
237+
let assert Ok(_) = barnacle.shutdown(barnacle_subject, 1000)
14238
}
15239
```
16240

@@ -22,3 +246,24 @@ Further documentation can be found at <https://hexdocs.pm/barnacle>.
22246
gleam run # Run the project
23247
gleam test # Run the tests
24248
```
249+
250+
If you would like to contribute, please open an issue or a PR. New strategies are
251+
welcome, though try to keep dependencies to a minimum.
252+
253+
## TODO
254+
255+
- [ ] Add new strategies
256+
- [ ] Kubernetes
257+
- [ ] Kubernetes with DNS
258+
- [ ] Multicast UDP gossip
259+
- [ ] `.hosts.erlang` file
260+
- [ ] Add a Fly.io example
261+
262+
## With thanks
263+
264+
A lot of inspiration came from the following projects:
265+
266+
- [libcluster](https://github.com/bitwalker/libcluster)
267+
- [nessie_cluster](https://github.com/ckreiling/nessie_cluster)
268+
269+
Thanks!

gleam.toml

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
name = "barnacle"
22
version = "1.0.0"
33

4-
# Fill out these fields if you intend to generate HTML documentation or publish
5-
# your project to the Hex package manager.
6-
#
7-
# description = ""
8-
# licences = ["Apache-2.0"]
9-
# repository = { type = "github", user = "", repo = "" }
4+
description = "Self-healing clusters for Gleam applications on the BEAM!"
5+
licences = ["MIT"]
6+
repository = { type = "github", user = "Pevensie", repo = "barnacle" }
107
# links = [{ title = "Website", href = "" }]
11-
#
12-
# For a full reference of all the available options, you can have a look at
13-
# https://gleam.run/writing-gleam/gleam-toml/.
148

159
[dependencies]
1610
gleam_stdlib = ">= 0.34.0 and < 2.0.0"

0 commit comments

Comments
 (0)