Reconciler Logic

作者 grafana1ccacf29049fApache-2.0279 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫今天更新

Implement reconcilers and watchers for grafana-app-sdk apps — write `TypedReconciler[*MyKind]` reconcile functions, apply generation-based skip patterns, do conflict-safe status updates via `resource.UpdateObject`, configure `BasicReconcileOptions` (namespace, label/field filters, finalizer management), use `Watcher` for event-style handling, reconcile `UnmanagedKinds` (resources your app doesn't own), and register the whole thing in `app.go`. Use when writing a reconciler, implementing the reconcile loop, adding async business logic, handling create/update/delete events, processing resource state changes, scheduling periodic resyncs with `RequeueAfter`, picking between Watcher and Reconciler, or wiring a controller into `app.go` — even when the user says "process this resource", "handle X events", or "write a controller" without saying "reconciler".

AI 產生的概覽

指導為 grafana-app-sdk 應用程式實作 reconciler 與 watcher,包含具型別的協調函式、狀態更新與 app.go 註冊。

功能
此技能提供撰寫 grafana-app-sdk 應用程式非同步業務邏輯層的說明。內容涵蓋 TypedReconciler 協調函式、以 generation 為基礎的跳過模式、透過 resource.UpdateObject 進行衝突安全的状态更新、BasicReconcileOptions(例如命名空間與標籤或欄位篩選)、finalizer 管理、Watcher 事件處理、UnmanagedKinds,以及在 app.go 中的註冊。它產出 Go 協調器程式碼與接線指引,而非可執行指令碼。
適用情境
適用於撰寫 reconciler 或 controller、實作協調迴圈、加入非同步業務邏輯、處理建立、更新或刪除事件、使用 RequeueAfter 安排週期性重新同步、在 Watcher 與 Reconciler 之間做選擇,或將 controller 接入 app.go 的情境。
執行需求
需要 grafana-app-sdk 與 Go 工具鏈;此技能本身不附帶指令碼,只有參考文件。它引用了 grafana-app-sdk 的 GitHub 儲存庫與 operator 套件文件。

Reconciler Logic

Reconcilers are the async business-logic layer of a grafana-app-sdk app. The SDK enqueues a reconcile event when a resource is created, updated, or deleted; the reconciler observes the current state and drives the system toward the desired state.

Common Workflows

Implementing a new reconciler end-to-end

bash
# 1. Generate operator stubs for a standalone appgrafana-app-sdk project component add operator
# 2. Implement the ReconcileFunc — see § TypedReconciler below for the pattern
# 3. Register the reconciler in app.go (see references/registration.md)
# 4. Generate, build, and verify it runsgrafana-app-sdk generatego build ./...go run ./cmd/operator   # tail logs — reconcile entries should appear when you kubectl-apply a resource

If the operator starts but no reconcile events fire when you create a resource:

  • Check BasicReconcileOptions.Namespace matches the resource's namespace
  • Check BasicReconcileOptions.LabelFilters / FieldSelectors — most "no events" issues are filter mismatches (kubectl get <resource> -o yaml to see labels)
  • Confirm the reconciler was attached to the right (latest) version of the kind

TypedReconciler — preferred pattern

operator.TypedReconciler handles type assertion and provides a strongly-typed ReconcileFunc:

go
type MyKindReconciler struct {    operator.TypedReconciler[*v1alpha1.MyKind]    client resource.Client}
func NewMyKindReconciler(client resource.Client) *MyKindReconciler {    r := &MyKindReconciler{client: client}    r.ReconcileFunc = r.reconcile  // wire the typed func    return r}
func (r *MyKindReconciler) reconcile(    ctx context.Context,    req operator.TypedReconcileRequest[*v1alpha1.MyKind],) (operator.ReconcileResult, error) {    obj := req.Object
    // Skip if already reconciled this generation    if obj.GetGeneration() == obj.Status.LastObservedGeneration &&       req.Action != operator.ReconcileActionDeleted {        return operator.ReconcileResult{}, nil    }
    log := logging.FromContext(ctx).With("name", obj.GetName(), "namespace", obj.GetNamespace())    log.Info("reconciling", "action", operator.ResourceActionFromReconcileAction(req.Action))
    if req.Action == operator.ReconcileActionDeleted {        return operator.ReconcileResult{}, nil    }
    // ... business logic ...
    // Atomic status update — see § Status updates below    _, err := resource.UpdateObject(ctx, r.client, obj.GetStaticMetadata().Identifier(),        func(obj *v1alpha1.MyKind, _ bool) (*v1alpha1.MyKind, error) {            obj.Status.LastObservedGeneration = obj.GetGeneration()            obj.Status.State = "Ready"            return obj, nil        },        resource.UpdateOptions{Subresource: "status"},    )    return operator.ReconcileResult{}, err}

ReconcileAction values: ReconcileActionCreated, ReconcileActionUpdated, ReconcileActionDeleted, ReconcileActionResynced.

To requeue after a delay (e.g. polling an external system):

go
return operator.ReconcileResult{RequeueAfter: 10 * time.Second}, nil

Status updates with resource.UpdateObject

Always use resource.UpdateObject for status writes — it fetches the latest version before applying your update function, avoiding 409 Conflict errors when multiple reconcile events race:

go
_, err := resource.UpdateObject(ctx, r.client, identifier,    func(obj *v1alpha1.MyKind, exists bool) (*v1alpha1.MyKind, error) {        obj.Status.LastObservedGeneration = obj.GetGeneration()        obj.Status.State = "Ready"        obj.Status.Message = ""        return obj, nil    },    resource.UpdateOptions{Subresource: "status"},)

Do not use client.Update for status — it sends the full object and races with spec changes made by users.

Generation-based skip

Check LastObservedGeneration at the top of the reconcile function to avoid re-processing unchanged resources:

go
if obj.GetGeneration() == obj.Status.LastObservedGeneration {    return operator.ReconcileResult{}, nil}

ReconcileOptions

Control informer behavior via BasicReconcileOptions on the AppManagedKind entry:

go
{    Kind:       mykindv1alpha1.MyKindKind(),    Reconciler: reconciler,    ReconcileOptions: simple.BasicReconcileOptions{        Namespace:      "my-namespace",          // watch one namespace; default is all        LabelFilters:   []string{"env=prod"},    // only reconcile matching resources        FieldSelectors: []string{"status.phase=Running"},        UsePlain:       false,                   // false = wrap in OpinionatedReconciler (default; manages finalizers)    },},

UsePlain: false (the default) wraps your reconciler in OpinionatedReconciler, which manages finalizers automatically so the SDK can guarantee clean deletion.

References

  • references/watchers.md [blocked] — Watcher alternative (event-style Add/Update/Delete callbacks) + decision matrix for watcher vs reconciler
  • references/unmanaged-kinds.md [blocked] — UnmanagedKinds for reconciling resources your app doesn't own, with UseOpinionated: false guidance and common failure modes
  • references/registration.md [blocked] — full app.go wiring (client setup, multi-version registration, ValidateManifest) + common failure modes

External resources

來源與署名

來源:grafana/skills位於skills/grafana-app-sdk/reconciler-logic提交1ccacf2

授權條款: Apache-2.0

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架

更多來自 grafana/skills 的技能

React 19 Plugin Migration

grafana

指導將 Grafana 外掛遷移至 React 19 相容,依序完成建置、相依性與原始碼修改步驟。

Software Development279今天更新

Plugin Bundle Size

grafana

指導使用 React.lazy、Suspense 與 webpack 程式碼分割來最佳化 Grafana 應用程式外掛的打包體積。

Software Development279今天更新

Grafana Scenes

grafana

使用 @grafana/scenes 框架建置 Grafana 外掛頁面,涵蓋場景、面板、變數與下鑽導覽。

Software Development279今天更新

Check Npm

grafana

對 JS/TS 儲存庫的 npm、yarn 或 pnpm 設定進行唯讀供應鏈強化稽核。

Security279今天更新

Mimir

grafana

指導架設與維運 Grafana Mimir,用於可擴充、多租戶、長期的 Prometheus 與 OTLP 指標儲存。

DevOps & Cloud279今天更新

K6 Trend Analysis

grafana

Analyze Grafana Cloud k6 test run trends over time. Detects slow metric drift (e.g., P95 latency creeping up while still passing thresholds), computes headroom to thresholds, flags anomalies, and recommends threshold tightening. Use when the user asks about test performance trends, wants to know if metrics are degrading, asks whether thresholds should be tightened, or wants a health check across recent runs for a specific test. Trigger on phrases like "how is my test trending", "is P95 getting worse", "check for performance regression", "should I tighten thresholds", "are my tests degrading", "show me trends for test X", "analyze my k6 test runs", or "is my test getting slower". Also trigger when a user asks to check all tests in a project -- run this skill once per test and synthesize.

待分類279今天更新