Skip to content

Commit bc4d005

Browse files
committed
DOC/MINOR: document the 'before' directive in dependencies example
Update the dependencies documentation and example to demonstrate the 'before' configuration option alongside 'after'. A new 'zeroth' process was added to the example YAML and test suite to verify the correct startup sequence (zeroth -> first -> second). This clarifies how 'before' acts as a mirror edge to 'after', which is particularly useful for inserting a service into the startup order without modifying existing process configurations. Additionally, minor updates were initiated in the restart-backoff documentation.
1 parent cc8975f commit bc4d005

6 files changed

Lines changed: 81 additions & 28 deletions

File tree

documentation/dependencies/README.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Dependencies
22

3-
`after:` controls startup ordering. A service listed in another's `after` is started first; gopherd computes the order with a topological sort.
3+
`after:` and `before:` control startup ordering. A service listed in another's `after` is started first; `before` is the same edge written from the other side. gopherd computes the order with a topological sort.
44

55
## Config
66

77
```yaml
8-
# Order startup with `after`: `first` runs before `second`.
8+
# Order startup with `after` and `before`: zeroth -> first -> second.
99
processes:
1010
- name: second
1111
command: /bin/sh
@@ -16,21 +16,28 @@ processes:
1616
command: /bin/sh
1717
args: ["-c", "echo first >> ORDERLOG && sleep 300"]
1818
on-failure: shutdown
19+
- name: zeroth
20+
command: /bin/sh
21+
args: ["-c", "echo zeroth >> ORDERLOG && sleep 300"]
22+
before: [first]
23+
on-failure: shutdown
1924
```
2025
2126
- `second` declares `after: [first]`, so gopherd starts `first` first.
27+
- `zeroth` declares `before: [first]` — the mirror form, useful when the
28+
inserted service is the one being added and the existing configs should
29+
stay untouched.
2230
- Declaration order in the file does not matter — the dependency graph does.
23-
- `after` orders startup only; use `requires` if a dependency failure should also fail the dependent.
31+
- `after`/`before` order startup only; use `requires` if a dependency failure should also fail the dependent.
2432

2533
## Expected behavior
2634

27-
- `first` starts and appends `first` to the log.
28-
- `second` starts afterward and appends `second`.
29-
- The log reads `first` then `second`.
35+
- `zeroth` starts first, then `first`, then `second`; the log reads
36+
`zeroth`, `first`, `second`.
3037

3138
## Test
3239

33-
`ORDERLOG` is replaced with a temp path via `RunConfig`. The test asserts gopherd starts `first` before `second` (the daemon's `started` lines). Note `after` orders gopherd's start calls; the echoes themselves run in separate shells, so use a `ready-check` when the dependent needs the dependency's work completed.
40+
`ORDERLOG` is replaced with a temp path via `RunConfig`. The test asserts gopherd's `started` lines appear in `zeroth`, `first`, `second` order. Note `after`/`before` order gopherd's start calls; the echoes themselves run in separate shells, so use a `ready-check` when the dependent needs the dependency's work completed.
3441

3542
```bash
3643
go test ./documentation/dependencies/ -v

documentation/dependencies/example.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Order startup with `after`: `first` runs before `second`.
1+
# Order startup with `after` and `before`: zeroth -> first -> second.
22
processes:
33
- name: second
44
command: /bin/sh
@@ -9,3 +9,9 @@ processes:
99
command: /bin/sh
1010
args: ["-c", "echo first >> ORDERLOG && sleep 300"]
1111
on-failure: shutdown
12+
# before: the mirror edge — zeroth starts ahead of first
13+
- name: zeroth
14+
command: /bin/sh
15+
args: ["-c", "echo zeroth >> ORDERLOG && sleep 300"]
16+
before: [first]
17+
on-failure: shutdown

documentation/dependencies/example_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,17 @@ func TestDependenciesExample(t *testing.T) {
4242
// second running implies gopherd reached it in the start sequence.
4343
d.WaitRunning("second", 5*time.Second)
4444

45-
// `after` guarantees gopherd's start order (fork/exec), not the order the
46-
// two shells reach their echo, so assert on the daemon's own log.
45+
// `after`/`before` guarantee gopherd's start order (fork/exec), not the
46+
// order the shells reach their echo, so assert on the daemon's own log.
4747
out := d.Output()
48+
zi := strings.Index(out, "started zeroth")
4849
fi := strings.Index(out, "started first")
4950
si := strings.Index(out, "started second")
50-
if fi == -1 || si == -1 {
51-
t.Fatalf("expected both start lines in daemon output, got: %q", out)
51+
if zi == -1 || fi == -1 || si == -1 {
52+
t.Fatalf("expected all three start lines in daemon output, got: %q", out)
53+
}
54+
if zi > fi {
55+
t.Errorf("expected zeroth (before: [first]) started before first, got: %q", out)
5256
}
5357
if fi > si {
5458
t.Errorf("expected first started before second, got: %q", out)

documentation/restart-backoff/README.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ processes:
1919
backoff-delay: 500ms
2020
backoff-factor: 2.0
2121
backoff-limit: 5s
22+
23+
- name: batch
24+
command: /usr/local/bin/batch-job
25+
on-success: restart
26+
on-failure: shutdown
27+
backoff-delay: 500ms
28+
backoff-limit: 5s
2229
```
2330
2431
- `backoff-delay` — delay before the first restart (default `500ms`).
@@ -28,21 +35,26 @@ processes:
2835
continue at this fixed pace forever. There is no retry count limit.
2936
- A run that survives longer than `backoff-limit` resets the counter, so a
3037
service that crashes once a day always restarts after `backoff-delay`.
31-
- `on-success: restart` also exists for workers that should rerun after a
32-
clean exit; the default `on-success` is `shutdown`.
38+
- `on-success: restart` (the `batch` service) reruns a worker after every
39+
clean exit with the same backoff pacing — a poor man's cron loop. The
40+
default `on-success` is `shutdown`, and a genuine failure still takes the
41+
container down via `on-failure: shutdown`.
3342

3443
## Expected behavior
3544

3645
- `flaky` crashes, gopherd logs the exit and restarts it after the backoff
3746
delay; `gopherd status` shows the `restarts=` counter climbing.
38-
- `app` and gopherd itself are unaffected by the crash loop.
47+
- `batch` exits 0, is rerun after the backoff delay, and its counter climbs
48+
the same way.
49+
- `app` and gopherd itself are unaffected by either loop.
3950

4051
## Test
4152

42-
Run level. The flaky placeholder is substituted with `/bin/false` (always
43-
exits 1) and the backoff shortened; the test polls `status` until the
44-
restart counter reaches 3, proving the restart loop, then checks the daemon
45-
is still healthy. SIGTERM yields a clean exit 0.
53+
Run level. The placeholders are substituted with `/bin/false` (flaky, always
54+
exits 1) and `/bin/true` (batch, always exits 0) and the backoff shortened;
55+
the test polls `status` until both restart counters reach 3, proving the
56+
crash-restart and clean-rerun loops, then checks the daemon is still
57+
healthy. SIGTERM yields a clean exit 0.
4658

4759
```bash
4860
go test ./documentation/restart-backoff/ -v

documentation/restart-backoff/example.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,11 @@ processes:
1313
backoff-delay: 500ms
1414
backoff-factor: 2.0
1515
backoff-limit: 5s
16+
17+
# batch worker: reruns after every clean exit, same backoff pacing
18+
- name: batch
19+
command: /usr/local/bin/batch-job
20+
on-success: restart
21+
on-failure: shutdown
22+
backoff-delay: 500ms
23+
backoff-limit: 5s

documentation/restart-backoff/example_test.go

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,26 @@ func readExample(t *testing.T, path string) string {
3535
}
3636

3737
// Counters only appear in the full status listing, not `status <name>`.
38-
var restartsRe = regexp.MustCompile(`(?m)^\s*flaky\s+\S+\s+exits=\d+ restarts=(\d+)`)
38+
// Counters only appear in the full status listing, not `status <name>`.
39+
func restartsOf(t *testing.T, d *doctest.Daemon, service string) int {
40+
t.Helper()
41+
re := regexp.MustCompile(`(?m)^\s*` + service + `\s+\S+\s+exits=\d+ restarts=(\d+)`)
42+
m := re.FindStringSubmatch(d.Command("status"))
43+
if m == nil {
44+
return 0
45+
}
46+
n, _ := strconv.Atoi(m[1])
47+
return n
48+
}
3949

40-
// The flaky placeholder becomes /bin/false (always exits 1); with a shortened
41-
// backoff the restart counter climbs while app and the daemon stay healthy.
50+
// flaky becomes /bin/false (crash loop) and batch /bin/true (clean-exit
51+
// rerun loop); with a shortened backoff both restart counters climb while
52+
// app and the daemon stay healthy.
4253
func TestRestartBackoff(t *testing.T) {
4354
cfg := readExample(t, "example.yml")
4455
cfg = strings.ReplaceAll(cfg, "/usr/local/bin/myapp", "sleep")
4556
cfg = strings.ReplaceAll(cfg, "/usr/local/bin/flaky-worker", "/bin/false")
57+
cfg = strings.ReplaceAll(cfg, "/usr/local/bin/batch-job", "/bin/true")
4658
cfg = strings.ReplaceAll(cfg, "backoff-delay: 500ms", "backoff-delay: 50ms")
4759
cfg = strings.ReplaceAll(cfg, "backoff-limit: 5s", "backoff-limit: 200ms")
4860

@@ -51,15 +63,19 @@ func TestRestartBackoff(t *testing.T) {
5163
d.WaitRunning("app", 5*time.Second)
5264

5365
deadline := time.Now().Add(10 * time.Second)
54-
restarts := 0
55-
for time.Now().Before(deadline) && restarts < 3 {
56-
if m := restartsRe.FindStringSubmatch(d.Command("status")); m != nil {
57-
restarts, _ = strconv.Atoi(m[1])
66+
var flaky, batch int
67+
for time.Now().Before(deadline) {
68+
flaky, batch = restartsOf(t, d, "flaky"), restartsOf(t, d, "batch")
69+
if flaky >= 3 && batch >= 3 {
70+
break
5871
}
5972
time.Sleep(100 * time.Millisecond)
6073
}
61-
if restarts < 3 {
62-
t.Fatalf("expected >=3 restarts within 10s, got %d", restarts)
74+
if flaky < 3 {
75+
t.Fatalf("expected >=3 flaky restarts within 10s, got %d", flaky)
76+
}
77+
if batch < 3 {
78+
t.Fatalf("expected >=3 batch reruns (on-success: restart) within 10s, got %d", batch)
6379
}
6480

6581
// crash loop must not take the supervisor or the healthy service down

0 commit comments

Comments
 (0)