Skip to content

Commit fed00ae

Browse files
authored
Merge pull request #14 from SenseUnit/cmd_output_retries
command output: retries option
2 parents 503be2c + 860bf95 commit fed00ae

File tree

2 files changed

+35
-21
lines changed

2 files changed

+35
-21
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ Configuration:
124124
* **`group`** (_uint64_) identifier of group.
125125
* **`command`** (_list of strings_) command and arguments.
126126
* **`timeout`** (_duration_) execution time limit for the command.
127+
* **`retries`** (_int_) attempts to retry failed command. Default is `1`.
127128
* **`wait_delay`** (_duration_) delay to wait for I/O to complete after process termination. Zero value disables I/O cancellation logic. Default is `100ms`.
128129

129130
### Configuration example
@@ -187,6 +188,7 @@ outputs:
187188
- "--group"
188189
- "1000"
189190
timeout: 5s
191+
retries: 3
190192

191193
```
192194

output/command.go

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type CommandConfig struct {
1919
Group *uint64
2020
Command []string
2121
Timeout time.Duration
22+
Retries *int
2223
WaitDelay *time.Duration `yaml:"wait_delay"`
2324
}
2425

@@ -27,6 +28,7 @@ type Command struct {
2728
group uint64
2829
command []string
2930
timeout time.Duration
31+
retries int
3032
waitDelay time.Duration
3133
syncQueue chan struct{}
3234
shutdown chan struct{}
@@ -49,11 +51,16 @@ func NewCommand(cfg *config.OutputConfig, bridge iface.GroupBridge) (*Command, e
4951
if cc.WaitDelay != nil {
5052
waitDelay = *cc.WaitDelay
5153
}
54+
retries := 1
55+
if cc.Retries != nil && *cc.Retries > 1 {
56+
retries = *cc.Retries
57+
}
5258
return &Command{
5359
bridge: bridge,
5460
group: *cc.Group,
5561
command: cc.Command,
5662
timeout: cc.Timeout,
63+
retries: retries,
5764
waitDelay: waitDelay,
5865
syncQueue: make(chan struct{}, 1),
5966
shutdown: make(chan struct{}),
@@ -117,6 +124,24 @@ func (o *Command) syncLoop() {
117124
}
118125

119126
func (o *Command) runCommand() {
127+
for i := 0; i < o.retries; i++ {
128+
err := o.runCommandAttempt()
129+
if err != nil {
130+
var ee *exec.ExitError
131+
if errors.As(err, &ee) {
132+
log.Printf("command %v exited with code %d", o.command, ee.ExitCode())
133+
} else {
134+
log.Printf("command %v run error: %v", o.command, err)
135+
}
136+
} else {
137+
log.Printf("command %v succeeded", o.command)
138+
return
139+
}
140+
}
141+
log.Printf("command %v all attempts failed!", o.command)
142+
}
143+
144+
func (o *Command) runCommandAttempt() error {
120145
ctx := context.Background()
121146
if o.timeout > 0 {
122147
ctx1, cancel := context.WithTimeout(ctx, o.timeout)
@@ -133,29 +158,16 @@ func (o *Command) runCommand() {
133158
}
134159
cmd.Stdin = &stdinBuf
135160

136-
err := func() error {
137-
stdout := newOutputForwarder("stdout", o.command)
138-
defer stdout.Close()
139-
cmd.Stdout = stdout
140-
141-
stderr := newOutputForwarder("stderr", o.command)
142-
defer stderr.Close()
143-
cmd.Stderr = stderr
161+
stdout := newOutputForwarder("stdout", o.command)
162+
defer stdout.Close()
163+
cmd.Stdout = stdout
144164

145-
log.Printf("starting sync command %v...", o.command)
146-
return cmd.Run()
147-
}()
165+
stderr := newOutputForwarder("stderr", o.command)
166+
defer stderr.Close()
167+
cmd.Stderr = stderr
148168

149-
if err != nil {
150-
var ee *exec.ExitError
151-
if errors.As(err, &ee) {
152-
log.Printf("command %v exited with code %d", o.command, ee.ExitCode())
153-
} else {
154-
log.Printf("command %v run error: %v", o.command, err)
155-
}
156-
} else {
157-
log.Printf("command %v succeeded", o.command)
158-
}
169+
log.Printf("starting sync command %v...", o.command)
170+
return cmd.Run()
159171
}
160172

161173
type outputForwarder struct {

0 commit comments

Comments
 (0)