Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afc07c5ac6 |
+28
-25
@@ -225,20 +225,16 @@ var errInterrupted = errors.New("interrupted before the command finished")
|
|||||||
// op's cleanup (removing decrypted scratch files) runs before the
|
// op's cleanup (removing decrypted scratch files) runs before the
|
||||||
// process exits; the wait is bounded by shutdownTimeout. report is
|
// process exits; the wait is bounded by shutdownTimeout. report is
|
||||||
// called with a failure so the caller can show it to the user before
|
// called with a failure so the caller can show it to the user before
|
||||||
// it becomes errReported.
|
// it becomes errReported. An interrupted op is not reported, whatever
|
||||||
//
|
// it returned; RunOperation returns errInterrupted instead.
|
||||||
// The run counts as interrupted unless op returned, without an
|
|
||||||
// interrupt having cancelled it, before RunWithApp returned. An
|
|
||||||
// interrupted op is not reported, whatever it returned; RunOperation
|
|
||||||
// returns errInterrupted instead.
|
|
||||||
func RunOperation(
|
func RunOperation(
|
||||||
ctx context.Context, opts AppOptions,
|
ctx context.Context, opts AppOptions,
|
||||||
op func(v *vaultik.Vaultik) error, report func(err error),
|
op func(v *vaultik.Vaultik) error, report func(err error),
|
||||||
) error {
|
) error {
|
||||||
var (
|
var (
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
finished bool // op returned before any interrupt cancelled it
|
failed bool
|
||||||
failed bool // op finished with an error
|
interrupted bool
|
||||||
)
|
)
|
||||||
|
|
||||||
opts.Invokes = append(opts.Invokes,
|
opts.Invokes = append(opts.Invokes,
|
||||||
@@ -251,19 +247,21 @@ func RunOperation(
|
|||||||
err := op(v)
|
err := op(v)
|
||||||
|
|
||||||
// Only stop, called from OnStop below, cancels the
|
// Only stop, called from OnStop below, cancels the
|
||||||
// Vaultik context, so a live context means no
|
// Vaultik context; before op has returned, that
|
||||||
// interrupt cancelled op. Check the context, not
|
// happens only on an interrupt. Check the context,
|
||||||
// err: an interrupted op need not return
|
// not err: an interrupted op need not return
|
||||||
// context.Canceled (`snapshot verify --json`
|
// context.Canceled (`snapshot verify --json`
|
||||||
// returns a verification failure).
|
// returns a verification failure).
|
||||||
if v.Context().Err() == nil {
|
switch {
|
||||||
if err != nil {
|
case v.Context().Err() != nil:
|
||||||
report(err)
|
mu.Lock()
|
||||||
}
|
interrupted = true
|
||||||
|
mu.Unlock()
|
||||||
|
case err != nil:
|
||||||
|
report(err)
|
||||||
|
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
finished = true
|
failed = true
|
||||||
failed = err != nil
|
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,6 +282,12 @@ func RunOperation(
|
|||||||
if !stop(ctx) {
|
if !stop(ctx) {
|
||||||
log.Warn("Shutdown timed out before the operation " +
|
log.Warn("Shutdown timed out before the operation " +
|
||||||
"finished; decrypted temporary files may remain")
|
"finished; decrypted temporary files may remain")
|
||||||
|
|
||||||
|
// op has not returned, so the app is stopping on
|
||||||
|
// an interrupt.
|
||||||
|
mu.Lock()
|
||||||
|
interrupted = true
|
||||||
|
mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -296,17 +300,16 @@ func RunOperation(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunWithApp returns only after the app was asked to stop, either by
|
// RunWithApp returns only after OnStop has waited for the goroutine
|
||||||
// an interrupt or by the goroutine's Shutdown call. When op finished
|
// to return, whether the shutdown came from op finishing or from an
|
||||||
// without being cancelled, the goroutine set finished before that
|
// interrupt, so the goroutine's write to failed or interrupted is in
|
||||||
// call. So if finished is unset here, an interrupt stopped the app,
|
// place by the time we read it. If OnStop timed out, the goroutine
|
||||||
// and op either returned after it was cancelled or is still running
|
// may still be running, and OnStop has set interrupted itself.
|
||||||
// because the shutdown timed out.
|
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case !finished:
|
case interrupted:
|
||||||
return errInterrupted
|
return errInterrupted
|
||||||
case failed:
|
case failed:
|
||||||
return errReported
|
return errReported
|
||||||
|
|||||||
Reference in New Issue
Block a user