Replace channel-based cancellation with context cancellation in provisioning progress display - #7004
Conversation
There was a problem hiding this comment.
Pull request overview
Replace the channel-based cancellation used for the provisioning progress goroutine with context.WithCancel, ensuring the goroutine exits cleanly before spinner shutdown.
Changes:
- Introduced
context.WithCancelfor progress cancellation instead of acancelProgresschannel. - Added a
sync.WaitGroupto wait for the progress goroutine to exit before stopping the spinner.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Wallace Breza (wbreza)
left a comment
There was a problem hiding this comment.
Code Review: PR #7004 — Replace channel-based cancellation with context cancellation
Downstream Impact Assessment
- Isolated change — Only BicepProvider uses progress reporting; other providers (Terraform, DevCenter) are unaffected
- Manager integration —
provisioning.Manager.Deploy()wraps this with its own StopSpinner atmanager.go:128, which continues to work correctly - No test coverage for the progress goroutine lifecycle, so the timer issue below wouldn't be caught by CI
Findings Summary
| Priority | Count |
|---|---|
| 🔴 Critical | 1 |
| 🟡 Medium | 1 |
| 🟢 Low | 1 |
| Total | 3 |
See inline comments for details.
✅ What Looks Good
context.WithCancelis the correct Go pattern for goroutine cancellation — much cleaner than the channel approachsync.WaitGroupensures the goroutine exits before spinner stops, eliminating the original race condition- Passing
progressCtxtoReportProgressmeans in-flight API calls abort promptly on cancellation - Change is well-scoped and isolated
Overall Assessment: The pattern change is sound, but the missing timer.Reset breaks continuous progress reporting.
87973b6 to
31ad403
Compare
…sioning progress display
31ad403 to
8a7cec3
Compare
Wallace Breza (wbreza)
left a comment
There was a problem hiding this comment.
Re-review: Approve
The code changes look solid. The context cancellation pattern is idiomatic Go, the critical timer.Reset concern from my previous review has been addressed, and the sync.WaitGroup ensures proper goroutine lifecycle management.
What Looks Good
context.WithCancel+sync.WaitGroupis the correct concurrency pattern —cancelProgress()is non-blocking,wg.Wait()guarantees cleanup orderingprogressCtxpassed toReportProgressenables prompt cancellation of in-flight API calls- Delay simplification (merging
initialDelay/regularDelayinto singledelay) is clean
Prior Review Status
| Finding | Status |
|---|---|
| [Critical] timer.Reset removed | ✅ Fixed |
| [Medium] Double StopSpinner | ℹ️ Acceptable — wg.Wait() eliminates the race |
![]()
Azure Dev CLI Install InstructionsInstall scriptsMacOS/Linux
bash: pwsh: WindowsPowerShell install MSI install Standalone Binary
MSI
Documentationlearn.microsoft.com documentationtitle: Azure Developer CLI reference
|
…sioning progress display (#7004) ## Summary Replace the `cancelProgress` channel in `BicepProvider.Deploy` with `context.WithCancel` for cancelling the progress-reporting goroutine. ## Impact Users will observe a faster progress update when the deployment is completed, but we're still polling for new progress operations (which is very common). ## Changes - **`bicep_provider.go`**: Use `context.WithCancel` instead of a channel. Use `sync.WaitGroup` to ensure the goroutine fully exits before stopping the spinner. ## Motivation The channel-based approach blocks the caller on `defer func() { cancelProgress <- true }()` until the goroutine finishes its current `ReportProgress` cycle. With context cancellation: - `cancelProgress()` returns immediately (broadcast signal via channel close) - In-flight API calls abort promptly via context - `wg.Wait()` ensures the goroutine exits before `StopSpinner` is called, eliminating the race where the goroutine could restart the spinner after it was stopped Contributes to #6915
Summary
Replace the
cancelProgresschannel inBicepProvider.Deploywithcontext.WithCancelfor cancelling the progress-reporting goroutine.Impact
Users will observe a faster progress update when the deployment is completed, but we're still polling for new progress operations (which is very common).
Changes
bicep_provider.go: Usecontext.WithCancelinstead of a channel. Usesync.WaitGroupto ensure the goroutine fully exits before stopping the spinner.Motivation
The channel-based approach blocks the caller on
defer func() { cancelProgress <- true }()until the goroutine finishes its currentReportProgresscycle. With context cancellation:cancelProgress()returns immediately (broadcast signal via channel close)wg.Wait()ensures the goroutine exits beforeStopSpinneris called, eliminating the race where the goroutine could restart the spinner after it was stoppedContributes to #6915