/
lock_do.go
115 lines (91 loc) · 2.73 KB
/
lock_do.go
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package clicommand
import (
"context"
"errors"
"fmt"
"time"
"github.com/buildkite/agent/v3/lock"
"github.com/urfave/cli"
)
const lockDoHelpDescription = `Usage:
buildkite-agent lock do [key]
Description:
Begins a do-once lock. Do-once can be used by multiple processes to
wait for completion of some shared work, where only one process should do
the work.
Note that this subcommand is only available when an agent has been started
with the ′agent-api′ experiment enabled.
′lock do′ will do one of two things:
- Print 'do'. The calling process should proceed to do the work and then
call ′lock done′.
- Wait until the work is marked as done (with ′lock done′) and print 'done'.
If ′lock do′ prints 'done' immediately, the work was already done.
Examples:
#!/bin/bash
if [[ $(buildkite-agent lock do llama) == 'do' ]]; then
# your critical section here...
buildkite-agent lock done llama
fi`
type LockDoConfig struct {
// Common config options
LockScope string `cli:"lock-scope"`
SocketsPath string `cli:"sockets-path" normalize:"filepath"`
LockWaitTimeout time.Duration `cli:"lock-wait-timeout"`
// Global flags
Debug bool `cli:"debug"`
LogLevel string `cli:"log-level"`
NoColor bool `cli:"no-color"`
Experiments []string `cli:"experiment" normalize:"list"`
Profile string `cli:"profile"`
}
func lockDoFlags() []cli.Flag {
flags := append(
[]cli.Flag{
cli.DurationFlag{
Name: "lock-wait-timeout",
Usage: "Sets a maximum duration to wait for a lock before giving up",
EnvVar: "BUILDKITE_LOCK_WAIT_TIMEOUT",
},
},
lockCommonFlags...,
)
return append(flags, globalFlags()...)
}
var LockDoCommand = cli.Command{
Name: "do",
Usage: "Begins a do-once lock",
Description: lockDoHelpDescription,
Flags: lockDoFlags(),
Action: lockDoAction,
}
func lockDoAction(c *cli.Context) error {
if c.NArg() != 1 {
fmt.Fprint(c.App.ErrWriter, lockDoHelpDescription)
return &SilentExitError{code: 1}
}
key := c.Args()[0]
ctx, cfg, _, _, done := setupLoggerAndConfig[LockDoConfig](context.Background(), c)
defer done()
if cfg.LockScope != "machine" {
return errors.New("only 'machine' scope for locks is supported in this version.")
}
if cfg.LockWaitTimeout != 0 {
cctx, canc := context.WithTimeout(ctx, cfg.LockWaitTimeout)
defer canc()
ctx = cctx
}
client, err := lock.NewClient(ctx, cfg.SocketsPath)
if err != nil {
return fmt.Errorf(lockClientErrMessage, err)
}
do, err := client.DoOnceStart(ctx, key)
if err != nil {
return fmt.Errorf("couldn't start do-once lock: %w", err)
}
if do {
_, err = fmt.Fprintln(c.App.Writer, "do")
} else {
_, err = fmt.Fprintln(c.App.Writer, "done")
}
return err
}