К основному содержанию
скилл CX Codex

reconciler-logic — скилл для Claude Code: что делает и как установить

Помогает создавать реконсилеры и вотчеры для приложений на grafana-app-sdk. Настраивает цикл согласования, атомарные обновления статуса и фильтры ресурсов.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add grafana/skills --skill reconciler-logic -a claude-code
Открыть на GitHub

Что делает reconciler-logic

Скилл даёт готовые паттерны для асинхронной бизнес-логики в приложениях на базе grafana-app-sdk. В основе лежит типизированный обработчик operator.TypedReconciler, который принимает события создания, обновления или удаления объектов. Инструкция показывает, как настроить пропуск повторной обработки через проверку LastObservedGeneration и как безопасно задерживать повторные попытки с помощью RequeueAfter.

Для записи статуса скилл требует использовать функцию resource.UpdateObject, а не client.Update. Обычный вызов client.Update перезаписывает весь объект целиком и конфликтует с правками спецификации от пользователей, возвращая ошибку 409 Conflict.

Отдельное внимание уделено связыванию компонентов в app.go. Настройки BasicReconcileOptions позволяют отбирать ресурсы по LabelFilters и FieldSelectors, ограничивать наблюдение конкретным пространством имён и автоматически управлять финализаторами через OpinionatedReconciler.

Какие задачи решает

  • написать типизированный цикл согласования для ресурса в grafana-app-sdk
  • предотвратить ошибки 409 Conflict при обновлении статуса через resource.UpdateObject
  • настроить фильтрацию событий по меткам и селекторам полей в BasicReconcileOptions
  • зарегистрировать реконсилер и контроллер оператора в app.go

Примеры запросов агенту

  • Напиши TypedReconciler для MyKind с обновлением статуса через resource.UpdateObject
  • Как настроить BasicReconcileOptions для фильтрации по env=prod и зарегистрировать контроллер в app.go?
  • Реализуй пропуск повторной обработки через LastObservedGeneration и добавь RequeueAfter

Как установить reconciler-logic

1Через Skills CLI (Vercel)

npx skills add grafana/skills --skill reconciler-logic -a claude-code

2Вручную: положить файлы

~/.claude/skills/reconciler-logic/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/reconciler-logic/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Из того же набора47

cost-management Скилл разбирает счёт Grafana Cloud по командам и сервисам и подсказывает, как урезать метрики, логи и трейсы. CX Codex +1 4 200установок k6-docs Скилл для составления и проверки документации k6, генерации типов TypeScript и подготовки заметок к релизу. CX Codex +1 4 200установок testing Настраивает проверки доступности, нагрузочные тесты k6 и наблюдаемость фронтенда через Grafana Cloud. Нужен перед релизом и для поиска сбоев. CX Codex +1 4 200установок cue-kind-definition Помогает описывать ресурсы приложения в CUE: схемы spec и status, версии, ограничения полей и кодогенерация через grafana-app-sdk. CX Codex +1 4 200установок app-sdk-concepts Скилл помогает начинать разработку приложений для Grafana App Platform: выбрать режим, создать каркас и связать CUE-схемы с Go-логикой. CX Codex +1 4 200установок adaptive-metrics Скилл для работы с правилами агрегации Adaptive Metrics: помогает уменьшить число активных серий в Grafana Cloud Metrics и разобраться с высоким счётом за Mimir. CX Codex +1 4 200установок private-connectivity Настраивает приватное подключение к Grafana Cloud через AWS PrivateLink, Azure Private Link, GCP Private Service Connect и PDC. Пригодится, когда телеметрия не должна идти через публичный интернет. CX Codex +1 4 100установок ml-ai Настраивает функции машинного обучения и ассистента в Grafana Cloud. Помогает включить прогнозирование метрик, поиск аномалий через DBSCAN и автоанализ инцидентов Sift. CX Codex +1 4 100установок

Похожие

kubernetes-operator Alireza Rezvani Дисциплина разработки Kubernetes-операторов: валидатор CRD, линтер reconcile-циклов и аудит Capability Levels. Пригодится, когда контроллер уже пишется, а не когда его только выбирают. ★ 28 733звёзд репо prometheus-grafana devops-skills Скилл помогает агенту поднять сбор метрик в Prometheus, писать запросы PromQL и собирать панели Grafana. Пригодится, когда в проект нужно добавить мониторинг. CX Codex +1 449установок loki-logging devops-skills Скилл помогает настроить Grafana Loki, Promtail и запросы LogQL прямо в проекте, без похода в документацию. CX Codex +1 330установок dashboard-builder affaan-m Скилл помогает создавать рабочие дашборды для Grafana и SigNoz на основе вопросов дежурного инженера, а не случайного списка метрик. CX Codex +1 4 800установок observability-designer Alireza Rezvani Генерирует дашборды Grafana и находит шумные алерты в конфигах мониторинга. Помогает подготовить базовую наблюдаемость для сервиса перед ростом нагрузки. 671установок monitor-setup Seth Hobson Слэш-команда, которая разворачивает сбор метрик Prometheus, дашборды Grafana, распределённую трассировку и агрегацию логов. CX Codex ★ 41 729звёзд репо

Рядом в теме «DevOps и инфраструктура»

Всё по теме «DevOps и инфраструктура» →

Вопросы о reconciler-logic

Как установить reconciler-logic в Claude Code?

Выполните команду npx skills add grafana/skills --skill reconciler-logic -a claude-code в терминале. После этого скилл станет доступен агенту.

Зачем нужен скилл reconciler-logic?

Он помогает писать асинхронную логику операторов на Go для grafana-app-sdk, включая обработку жизненного цикла ресурсов и безопасную синхронизацию состояния.

Почему для статуса нужно использовать resource.UpdateObject, а не client.Update?

Функция resource.UpdateObject запрашивает свежую версию объекта перед записью подресурса статуса. Метод client.Update отправляет весь манифест и вызывает ошибки 409 Conflict, если пользователь параллельно изменил spec.

Исходный текст

SKILL.md · Apache-2.0
---
name: reconciler-logic
license: Apache-2.0
description: 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".
---

# 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 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
```

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

## External resources

- [grafana-app-sdk GitHub](https://github.com/grafana/grafana-app-sdk)
- [operator package docs](https://pkg.go.dev/github.com/grafana/grafana-app-sdk/operator)

© grafana · Apache-2.0 · grafana/skills

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой