doc(audit): mark AdoptExistingResources race as CLOSED (2a7d6101)
Updated FORENSIC_ARCHITECTURE_AUDIT.md:
- Status table: AdoptExistingResources race ❌→✅ ЗАКРЫТ (2a7d6101)
- §1.3: rewritten as ЗАКРЫТ with end-to-end fix description
- Fragile Components: Manual Adoption → закрыто
- Risky Decisions table: Manual Adoption ❌→✅
- Production-Grade summary: AdoptExistingResources race закрыт
- §2 Stuck Failed Accumulation: ✅ ЗАКРЫТ
- §2 AdoptExistingResources Race: ✅ ЗАКРЫТ
- §3 P2: ✅ ЗАКРЫТ
- §5 Sharded mutex verdict: updated (race закрыт)
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
| Синхронный subscriber dispatch (onboarding latency) | ✅ ЗАКРЫТ | предыдущая сессия |
|
||||
| `DefaultNSResolver` только append (нет RemoveNamespace) | ✅ ЗАКРЫТ | предыдущая сессия |
|
||||
| Stuck-failed namespace без auto-recovery | ✅ ЗАКРЫТ | `919e8439` |
|
||||
| AdoptExistingResources race при rolling update | ❌ ОТКРЫТ | — |
|
||||
| AdoptExistingResources race при rolling update | ✅ ЗАКРЫТ | `2a7d6101` |
|
||||
| No Explicit State Machine (implicit phase transitions) | ⚠️ СМЯГЧЕНО | `919e8439` |
|
||||
| Sharded mutex (bottleneck при >500 concurrent tenant) | ⏳ BACKLOG | не актуально при текущей нагрузке |
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
## Workaround-Driven Decisions
|
||||
|
||||
- ~~**Track-Only Removal**~~ → **ЗАМЕНЕНО** на `DispatchRemove` — cleanup вызывается всегда.
|
||||
- **Manual Adoption**: При старте executor-ы делают adopt orphaned ресурсов — workaround для несовершенного lifecycle. Активная проблема (см. §1.3).
|
||||
- **Manual Adoption**: При старте executor-ы делают adopt orphaned ресурсов. Закрыто: `PreRegisterManagedNamespaces` обеспечивает полный NS snapshot до adopt/cleanup (§1.3).
|
||||
- **Explicit Reaper Loops**: `idleObjectReaper` чистит `FunctionServiceCache` вместо event-driven подхода. Приемлемо: `IsValid()` check достаточен при корректной работе per-NS informer-ов.
|
||||
|
||||
---
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
- **RBAC/SA Drift**: Неконсистентность между созданием и удалением SA/ролей при сбое в `deregisterNamespace`.
|
||||
- **Cache Invalidation**: `FunctionServiceCache` не очищается при `RemoveNamespace` — расчёт на `idleObjectReaper`. При высоком churn rate может накапливать stale записи быстрее, чем reaper убирает.
|
||||
- **Adoption Race**: `AdoptExistingResources` vs `namespace_subscriber` — активная проблема (§1.3).
|
||||
- **Adoption Race**: ~~`AdoptExistingResources` vs `namespace_subscriber` — активная проблема~~ — закрыто: `PreRegisterManagedNamespaces` перед adopt/cleanup (`2a7d6101`).
|
||||
- **Stuck Failed Phase**: ~~Namespace в `failed` не восстанавливается без рестарта~~ — закрыто: `RunReconciler` + полная цепочка error propagation (§1.4).
|
||||
|
||||
---
|
||||
@@ -95,7 +95,7 @@
|
||||
|---------|--------|------------|
|
||||
| Informer Lifecycle Management | ✅ Hardened | per-NS context cancel + RemoveNamespace во всех компонентах |
|
||||
| Centralized Mutex | ⚠️ Приемлемо | sharding в backlog, не актуально до >500 NS |
|
||||
| Manual Adoption | ❌ Активная проблема | race при rolling update |
|
||||
| Manual Adoption | ✅ Закрыто | race при rolling update (`2a7d6101`) |
|
||||
| No Explicit State Machine | ✅ Частично закрыто | stuck-failed закрыт (`919e8439`); явная state machine в backlog |
|
||||
| Eventual Consistency | ⚠️ Смягчено | параллельный dispatch уменьшает окно, но не устраняет |
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
- **Maturity**: Архитектурно зрелый, хорошо документированный, с явным reasoning и поэтапным внедрением.
|
||||
- **Complexity**: Высокая в синхронизации и lifecycle. Снижена за счёт формализации `RemoveNamespace` контракта.
|
||||
- **Maintainability**: Среднесрочная — без явной state machine сложность будет расти. Auto-recovery из failed работает.
|
||||
- **Production-Grade**: Близко — informer lifecycle корректен, dispatch параллелен, cleanup симметричен, stuck-failed закрыт. Основной gap: AdoptExistingResources race.
|
||||
- **Production-Grade**: Близко — informer lifecycle корректен, dispatch параллелен, cleanup симметричен, stuck-failed закрыт, AdoptExistingResources race закрыт.
|
||||
|
||||
---
|
||||
|
||||
@@ -155,18 +155,21 @@
|
||||
|
||||
---
|
||||
|
||||
### 1.3 Manual Adoption (AdoptExistingResources) — ❌ АКТИВНАЯ ПРОБЛЕМА
|
||||
### 1.3 Manual Adoption (AdoptExistingResources) — ✅ ЗАКРЫТ (коммит `2a7d6101`)
|
||||
|
||||
**Сценарий: гонка adoption vs watcher при старте**
|
||||
|
||||
1. Executor стартует. `AdoptExistingResources` берёт `DefaultNSResolver().Snapshot()` — только статические NS из env.
|
||||
2. Параллельно: `RunManagedNamespaceWatcher` → `BootstrapAndDispatch()` → `registerNamespace()` добавляет managed NS.
|
||||
3. `AdoptExistingResources` уже завершила loop — managed NS не попал в snapshot. Orphaned pods в tenant NS не приняты.
|
||||
4. `CleanupOldExecutorObjects` сочтёт старые pod-ы orphaned → удалит → cold start для всех функций.
|
||||
**Что было:** `AdoptExistingResources` и `CleanupOldExecutorObjects` запускались до `StartNSWatcher`. `DefaultNSResolver().Snapshot()` возвращал только статические NS из `FISSION_RESOURCE_NAMESPACES` → managed NS не покрывались:
|
||||
- Pods от предыдущего executor в managed NS не adoptировались (сохраняли старый `instanceID`) → poolmgr создавал новые pool pods → cold start.
|
||||
- Старые RS/deployments в managed NS не чистились → накапливались.
|
||||
|
||||
**При rolling update:** два executor-а параллельно патчат `instanceID` на одних pod-ах → race.
|
||||
**Что сделано:** `multitenant.PreRegisterManagedNamespaces(ctx, logger, kubernetesClient)` — синхронный `Namespaces.List` с label `fission.io/managed=true` вызывается в `executor.go` **до** goroutines adopt+cleanup. Добавляет все managed NS в `DefaultNSResolver`. Идемпотентен с последующим `AddFunc` из watcher. Не ломает при ошибке API (warn + proceed).
|
||||
|
||||
**Статус:** не исправлено. Требует либо задержки `AdoptExistingResources` до завершения первого `BootstrapAndDispatch`, либо включения managed NS в `Snapshot()` на момент adoption.
|
||||
**End-to-end после фикса:**
|
||||
1. `PreRegisterManagedNamespaces` → `DefaultNSResolver` содержит static + managed NS
|
||||
2. `AdoptExistingResources` → патчит pods в managed NS с новым `instanceID`
|
||||
3. `CleanupOldExecutorObjects` / `GetReaperNamespace()` → видит managed NS → чистит стale объекты
|
||||
4. `StartNSWatcher` → `AddFunc` срабатывает для тех же NS — `DefaultNSResolver().AddNamespace()` idempotent, `AddNamespace` executor types dedup-protected
|
||||
|
||||
---
|
||||
|
||||
@@ -226,13 +229,13 @@
|
||||
|
||||
100 NS × 5 informer-типов × LIST каждые 30 мин = **500 concurrent LIST** к Kubernetes API. Не изменилось, не исправлено.
|
||||
|
||||
### Stuck Failed Accumulation
|
||||
### Stuck Failed Accumulation — ✅ ЗАКРЫТ
|
||||
|
||||
10 ns/час × 1% API error rate = ~2.4 failed NS/сутки. ~72 за 30 дней. Не исправлено (§1.4).
|
||||
Failed NS автоматически ретраятся `RunReconciler` каждые 30с и выходят из `failed` при восстановлении API. Накопления больше не происходит.
|
||||
|
||||
### AdoptExistingResources Race
|
||||
### AdoptExistingResources Race — ✅ ЗАКРЫТ
|
||||
|
||||
При rolling update — race на `instanceID` патч. Не исправлено (§1.3).
|
||||
`PreRegisterManagedNamespaces` синхронно добавляет managed NS в `DefaultNSResolver` до adopt/cleanup. Старые pods adoptируются, stale объекты чистятся. Подробно — §1.3.
|
||||
|
||||
---
|
||||
|
||||
@@ -242,11 +245,11 @@
|
||||
|
||||
Error propagation исправлена во всей цепочке: `setupSAAndRoleBindings` → `EnsureNamespaceSA` → `registerNamespace` → executor subscriber. `RunReconciler` логирует retry и исход.
|
||||
|
||||
### P2 — AdoptExistingResources после BootstrapAndDispatch
|
||||
### P2 — AdoptExistingResources после BootstrapAndDispatch — ✅ ЗАКРЫТ (`2a7d6101`)
|
||||
|
||||
Либо: подождать первый `BootstrapAndDispatch()` через канал-сигнал, затем запускать `AdoptExistingResources`. Либо: в `AdoptExistingResources` использовать `NamespaceManager.Snapshot()` вместо `DefaultNSResolver().Snapshot()` (managed NS уже добавлены к этому моменту через BootstrapAndDispatch).
|
||||
`PreRegisterManagedNamespaces` вызывается синхронно до adopt/cleanup. Делает один `Namespaces.List(label=fission.io/managed=true)` → добавляет все managed NS в `DefaultNSResolver`. После этого adopt и cleanup покрывают полный tenant NS set.
|
||||
|
||||
**Влияние:** устраняет orphaned pods при холодном старте и rolling update.
|
||||
**Влияние:** устранены orphaned pods при холодном старте и resource leak (stale RS/deployments).
|
||||
|
||||
### P3 — NamespaceCondition на k8s Namespace объекте
|
||||
|
||||
@@ -273,4 +276,4 @@ Error propagation исправлена во всей цепочке: `setupSAAnd
|
||||
|
||||
**Технически реализуемо** без breaking interface change. Полный код — в `FORENSIC_ARCHITECTURE_AUDIT_LEGACY_2026-05.md §5`.
|
||||
|
||||
**Вердикт:** не оправдано при текущей нагрузке. Реальный bottleneck — AdoptExistingResources race, не mutex. Sharded mutex — в backlog, актуально при >500 concurrent tenant с >1 onboarding/sec.
|
||||
**Вердикт:** не оправдано при текущей нагрузке. Реальный bottleneck — AdoptExistingResources race — закрыт (`2a7d6101`). Sharded mutex — в backlog, актуально при >500 concurrent tenant с >1 onboarding/sec.
|
||||
|
||||
Reference in New Issue
Block a user