- ensureDeployment: Strategy Recreate (not RollingUpdate) — prevents H2 file lock when two pods mount same PVC simultaneously during rollout restart - preStop: sleep 3 — graceful H2 shutdown before SIGTERM - livenessProbe timeoutSeconds: 3 — prevents false positive on GC pause - terminationGracePeriodSeconds: 15 - doc: thinking log, ERR-SQS-06, progress.md, architecture SVG schema
79 lines
3.1 KiB
Python
79 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
# 2026-04-09 — v0.1.13: Strategy Recreate + preStop hook + liveness timeout fix
|
|
import sys
|
|
|
|
FILE = "/home/naeel/terra/sless/sqs-operator/internal/controller/queueservice_controller.go"
|
|
|
|
with open(FILE, "r") as f:
|
|
code = f.read()
|
|
|
|
# === PATCH 1: Strategy Recreate ===
|
|
old_1 = "\t\t\t},\n\t\t\tTemplate: corev1.PodTemplateSpec{"
|
|
new_1 = """\t\t\t},
|
|
\t\t\t// Recreate: старый pod убивается ДО создания нового.
|
|
\t\t\t// H2 MVStore держит FileChannel.lock() на /data/elasticmq.mv.db —
|
|
\t\t\t// при RollingUpdate два pod лезут в один PVC одновременно = ERR-SQS-06.
|
|
\t\t\tStrategy: appsv1.DeploymentStrategy{
|
|
\t\t\t\tType: appsv1.RecreateDeploymentStrategyType,
|
|
\t\t\t},
|
|
\t\t\tTemplate: corev1.PodTemplateSpec{"""
|
|
|
|
count = code.count(old_1)
|
|
if count != 1:
|
|
print(f"FAIL patch 1: found {count} matches for Selector close + Template")
|
|
sys.exit(1)
|
|
code = code.replace(old_1, new_1, 1)
|
|
print("PATCH 1 OK: Strategy Recreate")
|
|
|
|
# === PATCH 2: terminationGracePeriodSeconds ===
|
|
old_2 = "\t\t\t\t\tSecurityContext: &corev1.PodSecurityContext{\n\t\t\t\t\t\tFSGroup: func() *int64 { v := int64(999); return &v }(),\n\t\t\t\t\t},\n\t\t\t\t\tContainers: func() []corev1.Container {"
|
|
new_2 = """\t\t\t\t\tSecurityContext: &corev1.PodSecurityContext{
|
|
\t\t\t\t\t\tFSGroup: func() *int64 { v := int64(999); return &v }(),
|
|
\t\t\t\t\t},
|
|
\t\t\t\t\t// 15 сек — достаточно для graceful shutdown JVM + H2 fsync.
|
|
\t\t\t\t\tTerminationGracePeriodSeconds: func() *int64 { v := int64(15); return &v }(),
|
|
\t\t\t\t\tContainers: func() []corev1.Container {"""
|
|
|
|
count = code.count(old_2)
|
|
if count != 1:
|
|
print(f"FAIL patch 2: found {count} matches for SecurityContext + Containers")
|
|
sys.exit(1)
|
|
code = code.replace(old_2, new_2, 1)
|
|
print("PATCH 2 OK: terminationGracePeriodSeconds 15")
|
|
|
|
# === PATCH 3: LivenessProbe TimeoutSeconds=3 + preStop hook ===
|
|
old_3 = "\t\t\t\t\t\t\t\t\tInitialDelaySeconds: 5,\n\t\t\t\t\t\t\t\t\tPeriodSeconds: 10,\n\t\t\t\t\t\t\t\t\tFailureThreshold: 5,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}"
|
|
new_3 = """\t\t\t\t\t\t\t\t\tInitialDelaySeconds: 5,
|
|
\t\t\t\t\t\t\t\t\tPeriodSeconds: 10,
|
|
\t\t\t\t\t\t\t\t\tTimeoutSeconds: 3,
|
|
\t\t\t\t\t\t\t\t\tFailureThreshold: 5,
|
|
\t\t\t\t\t\t\t\t},
|
|
\t\t\t\t\t\t\t\t// preStop: 3 сек на graceful shutdown H2 перед SIGTERM.
|
|
\t\t\t\t\t\t\t\tLifecycle: &corev1.Lifecycle{
|
|
\t\t\t\t\t\t\t\t\tPreStop: &corev1.LifecycleHandler{
|
|
\t\t\t\t\t\t\t\t\t\tExec: &corev1.ExecAction{
|
|
\t\t\t\t\t\t\t\t\t\t\tCommand: []string{"sh", "-c", "sleep 3"},
|
|
\t\t\t\t\t\t\t\t\t\t},
|
|
\t\t\t\t\t\t\t\t\t},
|
|
\t\t\t\t\t\t\t\t},
|
|
\t\t\t\t\t\t\t},
|
|
\t\t\t\t\t\t}"""
|
|
|
|
count = code.count(old_3)
|
|
if count != 1:
|
|
print(f"FAIL patch 3: found {count} matches for LivenessProbe block")
|
|
sys.exit(1)
|
|
code = code.replace(old_3, new_3, 1)
|
|
print("PATCH 3 OK: timeoutSeconds=3 + preStop sleep 3")
|
|
|
|
# === PATCH 4: version ===
|
|
if "0.1.12" in code:
|
|
code = code.replace("0.1.12", "0.1.13")
|
|
print("PATCH 4 OK: version -> 0.1.13")
|
|
else:
|
|
print("PATCH 4 SKIP: version string not found")
|
|
|
|
with open(FILE, "w") as f:
|
|
f.write(code)
|
|
print("\nAll patches applied.")
|