v5.0.64: delete idempotency, duplicate adopt, defer unlock, exist marker
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# 2026-07-07 — Opus answers: duplicate/exist fix strategy
|
||||
|
||||
## Контекст
|
||||
Промпт из `/home/naeel/tf_provider/prompt_for_opus_duplicate.md`
|
||||
После mutex (v5.0.63) pg_user_5 упал: «Операция вернула duplicate/exist, но объект не найден в state_out»
|
||||
|
||||
## Корень всех проблем
|
||||
|
||||
Код путает два разных случая «не-found»:
|
||||
- `known && !found` — список в state_out ЕСТЬ, объекта нет → реальная несогласованность
|
||||
- `!known` — списка в state_out НЕТ вообще (PostgreSQL, Kafka) → проверить невозможно
|
||||
|
||||
Сейчас `!known` трактуется как несогласованность → ошибка.
|
||||
|
||||
---
|
||||
|
||||
## Вопрос 1 (ПРИОРИТЕТ) — ДА, доверять API при `!known`
|
||||
|
||||
**Где:** templates.go → генерится во все subresource Create
|
||||
|
||||
**Фикс:** усыновлять при `found || !known`, ошибку только для `known && !found`:
|
||||
```go
|
||||
if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
|
||||
found, known := false, false
|
||||
if targetValue != "" {
|
||||
var checkErr error
|
||||
found, known, checkErr = resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
|
||||
if checkErr != nil {
|
||||
resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
// found → подтверждено в state_out
|
||||
// !known → списка в state_out нет (PG/Kafka) → доверяем API
|
||||
// known&&!found → реальная несогласованность
|
||||
if found || !known {
|
||||
plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "{{.SubName}}", idParams))
|
||||
resp.Diagnostics.AddWarning("Подресурс усыновлён", "API вернул already exists; объект принят в state: "+targetValue)
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
|
||||
return
|
||||
}
|
||||
resp.Diagnostics.AddError("Нарушена консистентность", "API вернул duplicate/exist, но объект подтверждённо отсутствует в state_out: "+targetValue)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Вопрос 2 — ДА, нужен явный маппинг из метаданных
|
||||
|
||||
**Где:** subresource_guard.go — `SubresourceListKey` (эвристика `name+"s"`) и `SubresourceIdentityKey` (special-map на 2 сервиса)
|
||||
|
||||
**Доказательство:** Kafka — реальные ключи `kafkaUsers`/`kafkaTopics`, эвристика даёт `users`/`topics` → `known=false` даже когда данные есть.
|
||||
|
||||
**Фикс:** генератор должен эмитить явные `listKey`/`idKey` как константы из метаданных. Для сервисов без ключа в state_out (PostgreSQL) — эмитить `listKey=""` → `FindSubresourceInStateOut` → `known=false` → работает путь «доверять API» из Вопроса 1.
|
||||
|
||||
---
|
||||
|
||||
## Вопрос 3 — НЕТ, list-эндпоинтов не существует
|
||||
|
||||
**Проверено по API-метаданным** (svc 90):
|
||||
- Операции: create(19), delete(20), resume(114), suspend(115), recovery(47), modify(48), restart(54)
|
||||
- Subresource: create_user(241), delete_user(244), create_database(245), delete_database(246)
|
||||
- **Ни одной `list_*`/`get_*`/`show_*`**
|
||||
|
||||
Перечислить подресурсы через API невозможно. Единственный источник — state_out, а у PG его нет.
|
||||
|
||||
**Вывод:** стратегия «доверять API» (Вопрос 1) — единственно возможная.
|
||||
|
||||
---
|
||||
|
||||
## Вопрос 4 — Частично; текст ОК, нужен HTTP 409
|
||||
|
||||
**Где:** subresource_guard.go — `IsSubresourceAlreadyExistsError`
|
||||
|
||||
- `role "pg_user_5" already exists` → ловится ✅
|
||||
- `already exist` (без s), голый `exist` → НЕ ловится
|
||||
- **Главная дыра:** HTTP 409 без текста → НЕ ловится
|
||||
|
||||
**Фикс:**
|
||||
```go
|
||||
markers := []string{"уже существует", "already exists", "already exist", "duplicate", "conflict", " exist"}
|
||||
```
|
||||
Плюс проверка HTTP 409 (требует проброса статус-кода из клиента).
|
||||
|
||||
---
|
||||
|
||||
## Приоритет реализации
|
||||
|
||||
1. **Вопрос 1** — чинит `pg_user_5` сразу
|
||||
2. **Вопрос 2** — чинит Kafka и остальные
|
||||
3. **Вопрос 4** — устойчивость к формулировкам
|
||||
4. **Вопрос 3** — документировать как «невозможно, дизайн-решение»
|
||||
|
||||
Всё правится в шаблоне templates.go и subresource_guard.go. Сгенерированные файлы НЕ править — перегенерировать.
|
||||
|
||||
**Дата:** 2026-07-07
|
||||
**Статус:** анализ завершён, правки НЕ внесены
|
||||
Reference in New Issue
Block a user