stackruntime: Make sure PlanResponse and ApplyResponse channels get closed

The closure of these channels is how a caller knows that the operation has
completed, so we must always close them before we return or the caller
is likely to get wedged.
pull/34738/head
Martin Atkins 3 years ago
parent f34633577f
commit 8f00a7bf5a

@ -44,6 +44,13 @@ func Apply(ctx context.Context, req *ApplyRequest, resp *ApplyResponse) {
},
}
// Whatever return path we take, we must close our channels to allow
// a caller to see that the operation is complete.
defer func() {
close(resp.Diagnostics)
close(resp.AppliedChanges) // MUST be the last channel to close
}()
main, err := stackeval.ApplyPlan(
ctx,
req.Config,
@ -78,8 +85,6 @@ func Apply(ctx context.Context, req *ApplyRequest, resp *ApplyResponse) {
resp.Diagnostics <- diag
}
close(resp.Diagnostics)
close(resp.AppliedChanges) // MUST be the last channel to close
}
// ApplyRequest represents the inputs to an [Apply] call.

@ -26,9 +26,15 @@ import (
// through resp after passing it to this function, aside from the implicit
// modifications to the internal state of channels caused by reading them.
func Plan(ctx context.Context, req *PlanRequest, resp *PlanResponse) {
var respMu sync.Mutex // must hold this when accessing fields of resp, aside from channel sends
resp.Applyable = true // we'll reset this to false later if appropriate
var respMu sync.Mutex // must hold this when accessing fields of resp, aside from channel sends
// Whatever return path we take, we must close our channels to allow
// a caller to see that the operation is complete.
defer func() {
close(resp.Diagnostics)
close(resp.PlannedChanges) // MUST be the last channel to close
}()
main := stackeval.NewForPlanning(req.Config, stackeval.PlanOpts{
InputVariableValues: req.InputValues,
@ -66,9 +72,6 @@ func Plan(ctx context.Context, req *PlanRequest, resp *PlanResponse) {
resp.PlannedChanges <- &stackplan.PlannedChangeApplyable{
Applyable: resp.Applyable,
}
close(resp.Diagnostics)
close(resp.PlannedChanges) // MUST be the last channel to close
}
// PlanRequest represents the inputs to a [Plan] call.

Loading…
Cancel
Save