feat(service): timeout_sec без дефолта; 0=нет таймаута; operator v0.1.48
- api/v1alpha1/service_types.go: убрать +kubebuilder:default=30
- invoke.go: TimeoutSec=0 → &http.Client{} (без таймаута)
- services.go: валидация timeout_sec < 0 || > 900 → HTTP 400
- service_resource.go: TF schema Optional (без Computed); 0 → Int64Null()
- deployments/k8s/operator.yaml: v0.1.47 → v0.1.48
- doc/: progress.md + api/design.md (модель Service) + decisions/log.md
- examples/POSTGRES/: bug_hunter.sh, chaos_marathon.sh, chaos_marathon.tf
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# 2026-03-21 — py-retry-writer: пишет N строк с retry при PG ошибке.
|
||||
# Тестирует: устойчивость к transient PG errors (simulate_error=true), retry logic,
|
||||
# корректный rollback при частичном сбое.
|
||||
import os, time, psycopg2, random
|
||||
|
||||
_MAX_RETRIES = 3
|
||||
|
||||
def retry_write(event):
|
||||
n = min(int(event.get("n", 5)), 100)
|
||||
prefix = str(event.get("prefix", "retry"))[:40]
|
||||
# simulate_error: с вероятностью 30% кидает OperationalError на 2-й попытке
|
||||
simulate = str(event.get("simulate_error", "false")).lower() in ("true", "1")
|
||||
|
||||
attempt = 0
|
||||
last_err = None
|
||||
|
||||
while attempt < _MAX_RETRIES:
|
||||
attempt += 1
|
||||
try:
|
||||
conn = psycopg2.connect(
|
||||
host=os.environ["PGHOST"], port=int(os.environ.get("PGPORT", 5432)),
|
||||
dbname=os.environ["PGDATABASE"], user=os.environ["PGUSER"],
|
||||
password=os.environ["PGPASSWORD"], sslmode=os.environ.get("PGSSLMODE", "require"),
|
||||
)
|
||||
inserted = []
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
for i in range(n):
|
||||
# Симуляция: на первой попытке падаем с вероятностью 50%
|
||||
if simulate and attempt == 1 and i == n // 2:
|
||||
raise psycopg2.OperationalError("simulated transient error")
|
||||
title = f"{prefix}-{int(time.time()*1000)}-{i}-a{attempt}"
|
||||
cur.execute(
|
||||
"INSERT INTO terraform_demo_table (title) VALUES (%s) RETURNING id",
|
||||
(title,),
|
||||
)
|
||||
inserted.append(cur.fetchone()[0])
|
||||
conn.commit()
|
||||
return {
|
||||
"ok": True, "inserted": len(inserted),
|
||||
"attempts": attempt, "first_id": inserted[0] if inserted else None,
|
||||
}
|
||||
except Exception as e:
|
||||
conn.rollback()
|
||||
raise
|
||||
finally:
|
||||
conn.close()
|
||||
except psycopg2.OperationalError as e:
|
||||
last_err = str(e)
|
||||
if attempt < _MAX_RETRIES:
|
||||
time.sleep(0.3 * attempt) # exponential backoff
|
||||
continue
|
||||
|
||||
return {"ok": False, "attempts": attempt, "last_error": last_err}
|
||||
@@ -0,0 +1 @@
|
||||
psycopg2-binary
|
||||
Reference in New Issue
Block a user