-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinit_command.go
More file actions
63 lines (60 loc) · 2.44 KB
/
Copy pathinit_command.go
File metadata and controls
63 lines (60 loc) · 2.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// Boot-time init-command bridge: invokes an operator-supplied
// executable once, synchronously, so the script can populate the
// cache from a source of truth via the same HTTP endpoints any
// other client uses (/append, /warm, /rebuild). The full boot-flow
// contract — private socket, public-listener bind ordering, failure
// handling — lives in scopecache-core-rfc.md §2.7. This file owns
// the code-level invariants only.
//
// Adapter contract: both adapters wrap RunInitCommand in their own
// runInitWithPrivateSocket helper that binds a temp AF_UNIX socket
// serving the cache routes, sets SCOPECACHE_SOCKET_PATH in
// extraEnv, runs the script, then tears the socket down. The
// script reaches the cache via
// `curl --unix-socket "$SCOPECACHE_SOCKET_PATH" http://localhost/...`
// regardless of deployment shape.
//
// Cancellation: ctx is the caller's cancellation handle (typically
// a SIGINT/SIGTERM signal context, or caddy.Context for the
// module). Cancellation SIGKILLs the entire process group via
// configureProcessGroup so child processes from
// `curl ... &; wait` shapes do not leak. No default timeout —
// large-dataset rebuilds can legitimately take minutes; callers
// wrap with context.WithTimeout when they want a hard cap.
//
// Errors are logged and returned: the caller decides whether a
// failed init is fatal or recoverable. stdout/stderr are inherited.
// logf may be nil — the helper then runs without lifecycle logging.
package scopecache
import (
"context"
"fmt"
"os"
"os/exec"
)
// RunInitCommand executes command synchronously, blocking until it
// exits or ctx is cancelled. Returns nil when command is empty
// (sentinel for "not configured") or cmd.Run succeeds; otherwise
// returns the exec error wrapped with the command path. See
// file-header for the adapter, cancellation, and logging contracts.
func (g *Gateway) RunInitCommand(ctx context.Context, command string, extraEnv []string, logf func(string, ...any)) error {
if command == "" {
return nil
}
if logf == nil {
logf = func(string, ...any) {}
}
logf("init: running %s", command)
cmd := exec.CommandContext(ctx, command)
cmd.Env = append(os.Environ(), extraEnv...)
cmd.Stdin = nil
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
configureProcessGroup(cmd)
if err := cmd.Run(); err != nil {
logf("init: %s: %v", command, err)
return fmt.Errorf("scopecache init command %s: %w", command, err)
}
logf("init: %s: completed", command)
return nil
}