Files
traefik-selectel/internal/reconciler/loop.go
T
vasyanskandClaude Sonnet 5 273cd54415
Build / Tests (push) Successful in 13s
Build / Build image (push) Failing after 15s
Build / Notify on failure (push) Failing after 0s
feat: traefik-selectel-dns — A-записи Selectel по роутам Traefik + CI сборка образа
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 21:50:07 +07:00

62 lines
1.7 KiB
Go

package reconciler
import (
"context"
"time"
)
// CycleTimeout — верхняя граница одного цикла reconcile.
const CycleTimeout = 5 * time.Minute
// Run запускает цикл: сразу, затем каждые interval, а также по сигналу trigger
// (после debounce, чтобы схлопнуть пачку событий). Блокируется до отмены ctx.
// report вызывается после каждого цикла.
func (r *Reconciler) Run(ctx context.Context, interval, debounce time.Duration, trigger <-chan struct{}, report func(Result, error)) {
cycle := func() {
cctx, cancel := context.WithTimeout(ctx, CycleTimeout)
defer cancel()
res, err := r.Reconcile(cctx)
if err != nil {
r.log.Error("цикл reconcile завершён с ошибками", "error", err)
} else {
r.log.Info("цикл reconcile завершён",
"created", res.Created, "updated", res.Updated, "deleted", res.Deleted,
"unchanged", res.Unchanged, "skippedForeign", res.SkippedForeign,
"skippedConflict", res.SkippedConflict, "pendingDelete", res.PendingDelete)
}
if report != nil {
report(res, err)
}
}
cycle()
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
cycle()
case <-trigger:
if debounce > 0 {
t := time.NewTimer(debounce)
select {
case <-ctx.Done():
t.Stop()
return
case <-t.C:
}
}
// схлопываем накопившиеся сигналы
select {
case <-trigger:
default:
}
r.log.Debug("reconcile по событию Docker")
cycle()
ticker.Reset(interval)
}
}
}