一键导入
custom-poller-migration
Assist in migrating legacy pluginsdk.Retry() and pluginsdk.StateChangeConf.WaitForStateContext() logic to custom pollers.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Assist in migrating legacy pluginsdk.Retry() and pluginsdk.StateChangeConf.WaitForStateContext() logic to custom pollers.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Maintain this repository's changelog taxonomy, entry wording, and release-section structure. Use when adding or editing CHANGELOG.md entries, preparing a release section, or normalizing changelog entries to the repo taxonomy.
Write or update terraform-provider-azurerm documentation pages (website/docs/**/*.html.markdown) in HashiCorp style. Use when creating/updating resource or data source docs, fixing docs lint issues, or when you need to find correct argument/attribute descriptions.
Workflow false-positive-defense pass for code reviews — challenge existing findings, defend intentional design, inspect trust boundaries, and add evidence-backed advocate commentary before moderation freezes the output.
Design-direction workflow-governed review pass for code reviews — assess structural fit, schema and naming direction, and long-term maintainability, raising mandatory-source-backed Issues and otherwise recording direction as Observations before review output is frozen. Use when a code-review workflow should be checked for design fit.
Read-only workflow coordinator for code reviews — build a deterministic coverage matrix from authoritative changed-file scope, identify lifecycle/control windows and overlapping ownership surfaces, and require completion of mandatory issue-class checks before findings can freeze. Use when a code-review workflow must avoid active-file bias and keep review coverage order stable across reruns.
Final moderation and synthesis pass for code reviews — merge schema-conformant workflow findings, deduplicate overlaps, normalize severity and wording, and produce a final merged-and-normalized finding set. Use when a code-review workflow already has structured handoff records and needs deterministic moderation.
| name | custom-poller-migration |
| description | Assist in migrating legacy pluginsdk.Retry() and pluginsdk.StateChangeConf.WaitForStateContext() logic to custom pollers. |
When migrating polling logic under internal/**, use .github/instructions/implementation-compliance-contract.instructions.md as the single source of truth for:
IMPL-* rule familiesDo not treat this skill as a second independent compliance source.
This skill is a specialist companion to .github/skills/resource-implementation/SKILL.md, not a replacement for it.
Before applying this skill, read this file to EOF.
Before editing polling logic with this skill, complete this checklist:
.github/instructions/implementation-compliance-contract.instructions.md to EOF and applied the relevant IMPL-* rules.If preflight is incomplete, do not proceed with implementation work.
Use this skill when the task under internal/**/*.go involves migrating or replacing legacy polling logic, especially when you encounter:
pluginsdk.Retry()pluginsdk.StateChangeConfWaitForStateContext()pollers.PollerTypeWhen (and only when) this skill is invoked, the assistant MUST append the following line to the end of the assistant's final response:
Skill used: custom-poller-migration
Rules:
Skill used: ... line.You will typically encounter two legacy polling patterns.
pluginsdk.Retry()This loop repeatedly runs a function until it succeeds or hits a non-retryable error, often checking specific HTTP failure conditions.
err = pluginsdk.Retry(d.Timeout(pluginsdk.TimeoutCreate), func() *pluginsdk.RetryError {
resp, err := client.CreateOrUpdate(ctx, id, params)
if err != nil {
if response.WasBadRequest(resp.HttpResponse) {
return pluginsdk.RetryableError(err)
}
return pluginsdk.NonRetryableError(err)
}
return nil
})
pluginsdk.StateChangeConfThis structure polls an API via Refresh until the returned state enters the configured Target set, remaining in a Pending state otherwise.
stateConf := &pluginsdk.StateChangeConf{
Pending: []string{"404"},
Target: []string{"200"},
Refresh: func() (interface{}, string, error) {
resp, err := client.Get(ctx, id)
if err != nil {
if response.WasNotFound(resp.HttpResponse) {
return resp, strconv.Itoa(resp.HttpResponse.StatusCode), nil
}
return nil, "0", fmt.Errorf("polling for %s: %+v", id, err)
}
return resp, strconv.Itoa(resp.HttpResponse.StatusCode), nil
},
}
if _, err := stateConf.WaitForStateContext(ctx); err != nil {
return err
}
A custom poller must implement pollers.PollerType, specifically Poll(ctx context.Context) (*pollers.PollResult, error).
Place the poller in a custompollers package under the relevant service when that matches the existing provider pattern.
package custompollers
import (
"context"
"fmt"
"net/http"
"time"
"github.com/hashicorp/go-azure-sdk/sdk/client/pollers"
)
var _ pollers.PollerType = &examplePoller{}
type examplePoller struct {
client *service.Client
id service.IdType
}
func NewExamplePoller(cli *service.Client, id service.IdType) *examplePoller {
return &examplePoller{
client: cli,
id: id,
}
}
Never use a package-level shared pollers.PollResult variable. Always return a fresh pollers.PollResult{} directly to avoid concurrency bugs.
func (p examplePoller) Poll(ctx context.Context) (*pollers.PollResult, error) {
resp, err := p.client.Get(ctx, p.id)
if err != nil {
if response.WasNotFound(resp.HttpResponse) {
return &pollers.PollResult{
Status: pollers.PollingStatusInProgress,
PollInterval: 10 * time.Second,
}, nil
}
return nil, fmt.Errorf("checking state: %+v", err)
}
if resp.StatusCode == http.StatusOK {
return &pollers.PollResult{
Status: pollers.PollingStatusSucceeded,
PollInterval: 10 * time.Second,
}, nil
}
return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode)
}
Replace the old polling block with the custom poller.
poller := custompollers.NewExamplePoller(client, id)
if err := pollers.PollUntilDone(ctx, poller); err != nil {
return fmt.Errorf("waiting for state: %+v", err)
}
resp.Pollerresp, err := client.CreateOrUpdate(ctx, id, params)
if err != nil {
return fmt.Errorf("creating resource: %+v", err)
}
if err := resp.Poller.PollUntilDone(ctx); err != nil {
return fmt.Errorf("waiting for completion: %+v", err)
}
When asked to perform a polling migration, provide: