kin: auto-commit after pipeline
This commit is contained in:
parent
396f5193d3
commit
18160de45e
9 changed files with 449 additions and 0 deletions
|
|
@ -1177,6 +1177,38 @@ def _execute_department_head_step(
|
|||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Watchdog helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
import errno as _errno
|
||||
|
||||
|
||||
def _check_parent_alive(
|
||||
conn: sqlite3.Connection,
|
||||
pipeline: dict,
|
||||
task_id: str,
|
||||
project_id: str,
|
||||
) -> bool:
|
||||
"""Check if parent process is alive. Returns True if pipeline should abort.
|
||||
|
||||
Only treats ESRCH (no such process) as dead parent.
|
||||
PermissionError (pid 1 / init) and ValueError are ignored — pipeline continues.
|
||||
"""
|
||||
ppid = os.getppid()
|
||||
try:
|
||||
os.kill(ppid, 0)
|
||||
except OSError as exc:
|
||||
if exc.errno == _errno.ESRCH:
|
||||
reason = f"Parent process died unexpectedly (PID {ppid})"
|
||||
_logger.warning("Pipeline %s: %s — aborting", pipeline["id"], reason)
|
||||
models.update_pipeline(conn, pipeline["id"], status="failed")
|
||||
models.update_task(conn, task_id, status="blocked", blocked_reason=reason)
|
||||
return True
|
||||
# PermissionError (EPERM) — process exists but we can't signal it: continue
|
||||
return False
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pipeline executor
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -1234,6 +1266,9 @@ def run_pipeline(
|
|||
pipeline = models.create_pipeline(
|
||||
conn, task_id, project_id, route_type, steps,
|
||||
)
|
||||
# Save PID so watchdog can detect dead subprocesses (KIN-099)
|
||||
models.update_pipeline(conn, pipeline["id"], pid=os.getpid())
|
||||
pipeline["pid"] = os.getpid()
|
||||
models.update_task(conn, task_id, status="in_progress")
|
||||
|
||||
results = []
|
||||
|
|
@ -1248,6 +1283,19 @@ def run_pipeline(
|
|||
model = step.get("model", "sonnet")
|
||||
brief = step.get("brief")
|
||||
|
||||
# Check parent process is still alive (KIN-099 watchdog)
|
||||
if not dry_run and pipeline:
|
||||
if _check_parent_alive(conn, pipeline, task_id, project_id):
|
||||
return {
|
||||
"success": False,
|
||||
"error": "parent_process_died",
|
||||
"steps_completed": i,
|
||||
"total_cost": total_cost,
|
||||
"total_tokens": total_tokens,
|
||||
"total_duration": total_duration,
|
||||
"results": results,
|
||||
}
|
||||
|
||||
# Worktree isolation: opt-in per project, for write-capable roles
|
||||
_WORKTREE_ROLES = {"backend_dev", "frontend_dev", "debugger"}
|
||||
worktree_path = None
|
||||
|
|
|
|||
|
|
@ -332,3 +332,11 @@ routes:
|
|||
dept_marketing:
|
||||
steps: [marketing_head]
|
||||
description: "Marketing task routed through department head"
|
||||
|
||||
dept_infra:
|
||||
steps: [infra_head]
|
||||
description: "Infrastructure task routed through department head"
|
||||
|
||||
dept_research:
|
||||
steps: [research_head]
|
||||
description: "Research task routed through department head"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue