Skip to content

[Copilot] Timeout and Polling Issues #818

Open
@mawasile

Description

@mawasile

Timeout and Polling Issues

This document consolidates all issues related to timeout and polling mechanisms in the Terraform Provider for Power Platform.

ISSUE 1

Polling Loop Without Timeout or Delay Customization

File: /workspaces/terraform-provider-power-platform/internal/services/environment_wave/api_environment_wave.go

Problem: The polling loop inside UpdateFeature will continue indefinitely until the state changes or an error occurs. There is no timeout or maximum number of retries.

Impact: Potential for the function to hang indefinitely if the upgrade never completes, which is a significant operational risk. Severity: high

Location: Within the UpdateFeature method, the polling loop:

 for {
  feature, err := client.GetFeature(ctx, environmentId, featureName)
  ...
  err = client.Api.SleepWithContext(ctx, retryAfter)
  ...
 }

Code Issue:

 retryAfter := api.DefaultRetryAfter()
 for {
  feature, err := client.GetFeature(ctx, environmentId, featureName)
  if err != nil {
   return nil, err
  }

  if feature != nil && feature.AppsUpgradeState != "Upgrading" {
   tflog.Info(ctx, fmt.Sprintf("Feature %s  with state: %s", featureName, feature.AppsUpgradeState))
   return feature, nil
  }

  err = client.Api.SleepWithContext(ctx, retryAfter)
  if err != nil {
   return nil, err
  }

  tflog.Debug(ctx, fmt.Sprintf("Feature %s not yet enabled, polling...", featureName))
 }

Fix: Add context deadline/timeout or a maximum number of retries to prevent infinite loops:

 attempts := 0
 maxAttempts := 20
 retryAfter := api.DefaultRetryAfter()

 for attempts < maxAttempts {
  feature, err := client.GetFeature(ctx, environmentId, featureName)
  if err != nil {
   return nil, err
  }

  if feature != nil && feature.AppsUpgradeState != "Upgrading" {
   tflog.Info(ctx, fmt.Sprintf("Feature %s  with state: %s", featureName, feature.AppsUpgradeState))
   return feature, nil
  }

  err = client.Api.SleepWithContext(ctx, retryAfter)
  if err != nil {
   return nil, err
  }

  tflog.Debug(ctx, fmt.Sprintf("Feature %s not yet enabled, polling...", featureName))
  attempts++
 }
 return nil, fmt.Errorf("timed out waiting for feature %s to be enabled in environment %s", featureName, environmentId)

Or use the context deadline with ctx.Done() in the loop.

To finish the task you have to

  1. Run linter and fix any issues
  2. Run UnitTest and fix any of failing ones
  3. Generate docs
  4. Run Changie

Changie Instructions

Create only one change log entry. Do not run the changie tool multiple times.

changie new --kind <kind_key> --body "<description>" --custom Issue=<issue_number>

Where:

  • <kind_key> is one of: breaking, changed, deprecated, removed, fixed, security, documentation
  • <description> is a clear explanation of what was fixed/changed search for 'copilot-commit-message-instructions.md' how to write description.
  • <issue_number> pick the issue number or PR number

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingcopilotfixed using GitHub copilot autonomous agentenhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions