mcpField
R
reconciler-logic

reconciler-logic

github.com/grafana开发2954.3k 次安装1 天前更新
代码仓库

关于 reconciler-logic

面向 grafana-app-sdk 应用开发者的 Reconciler 实现指南,涵盖类型化处理、事件筛选、状态更新与 finalizer 行为,用于构建资源生命周期逻辑。

主要功能

  1. 01类型化 Reconciler 模式
  2. 02事件与操作类型处理
  3. 03避免状态更新冲突
  4. 04命名空间与标签筛选
  5. 05重新入队与代次检查

适用场景

  1. 01实现资源 Reconciler
  2. 02减少状态写入冲突
  3. 03排查未触发的协调事件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/grafana/skills --skill reconciler-logic

安装后在 Claude Code 中输入/reconciler-logic确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
informer-configuration.md
reconciler-patterns.md
registration.md
unmanaged-kinds.md
watchers.md

详细介绍

协调器逻辑

协调器是 grafana-app-sdk 应用的异步业务逻辑层。创建、更新或删除资源时,SDK 会将协调事件加入队列;协调器会观察当前状态,并推动系统达到期望状态。

常见工作流

端到端实现新的协调器
# 1. Generate operator stubs for a standalone app
grafana-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 runs
grafana-app-sdk generate
go build ./...
go run ./cmd/operator   # tail logs — reconcile entries should appear when you kubectl-apply a resource

如果 Operator 已启动,但创建资源时没有触发任何协调事件:

  • 检查 BasicReconcileOptions.Namespace 是否与资源的命名空间匹配
  • 检查 BasicReconcileOptions.LabelFilters / FieldSelectors——大多数“没有事件”的问题都是筛选条件不匹配(使用 kubectl get <resource> -o yaml 查看标签)
  • 确认协调器已关联到该 kind 的正确(最新)版本

TypedReconciler——首选模式

operator.TypedReconciler 会处理类型断言,并提供强类型的 ReconcileFunc:

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 的取值:ReconcileActionCreated、ReconcileActionUpdated、ReconcileActionDeleted、ReconcileActionResynced。

若要在延迟后重新入队(例如轮询外部系统):

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

使用 resource.UpdateObject 更新状态

写入状态时始终使用 resource.UpdateObject——它会先获取最新版本,再应用更新函数,从而避免多个协调事件并发时出现 409 Conflict 错误:

_, 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"},
)

不要使用 client.Update 更新状态——它会发送整个对象,并与用户对 spec 所做的更改产生竞争。

基于 Generation 跳过处理

在协调函数开头检查 LastObservedGeneration,避免重新处理未更改的资源:

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

ReconcileOptions

通过 AppManagedKind 条目中的 BasicReconcileOptions 控制 informer 行为:

{
    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(默认值)会将协调器包装在 OpinionatedReconciler 中,由它自动管理 finalizer,以便 SDK 确保资源被彻底删除。

参考资料

  • references/watchers.md — Watcher 替代方案(采用事件风格的 Add/Update/Delete 回调)以及 watcher 与协调器的选择矩阵
  • references/unmanaged-kinds.md — 使用 UnmanagedKinds 协调应用不拥有的资源,并说明 UseOpinionated: false 的用法和常见故障模式
  • references/registration.md — 完整的 app.go 配置(客户端设置、多版本注册、ValidateManifest)以及常见故障模式

外部资源

评论

支持 Markdown