From 3a9964c0e2bd85c8dbebccc8175af8e4042b5db7 Mon Sep 17 00:00:00 2001 From: Godopu Date: Fri, 10 Jul 2026 09:21:07 +0900 Subject: [PATCH] fix(deploy): resolve SQL timeouts, YAML drift, and orphaned tmux sessions - lib.sh: update atomic_dump_yaml to sync with YAML on any active session status change; set reader timeouts to 60.0s - create_session.sh: add exit trap cleanup_tmux_on_error to rollback spawned tmux sessions on initialization failures - reconcile.sh, update_yaml_resumed.sh, status.sh, stop_session.sh: align SQLite connection timeout values to 60.0s --- .agents/skills/lib.sh | 20 ++++++++++--------- .../scripts/create_session.sh | 12 +++++++++++ .../scripts/reconcile.sh | 2 +- .../scripts/update_yaml_resumed.sh | 2 +- .../multi-agent-mux-status/scripts/status.sh | 2 +- .../scripts/stop_session.sh | 2 +- 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/.agents/skills/lib.sh b/.agents/skills/lib.sh index 4330a6b..f083d4c 100644 --- a/.agents/skills/lib.sh +++ b/.agents/skills/lib.sh @@ -115,7 +115,7 @@ yaml_path = os.environ['YAML_PATH'] db_path = os.path.splitext(yaml_path)[0] + '.db' try: if os.path.exists(db_path): - conn = sqlite3.connect(db_path, timeout=10.0) + conn = sqlite3.connect(db_path, timeout=60.0) try: row = conn.execute('SELECT data FROM sessions WHERE name=?', (name,)).fetchone() if row: @@ -315,6 +315,9 @@ def _validate(d): def get_terminal_set(d): return {s.get('name'): s.get('status') for s in d.get('tmux_sessions', []) if s.get('status') in ('stopped', 'terminated', 'archived')} +def get_all_sessions_status(d): + return {s.get('name'): s.get('status') for s in d.get('tmux_sessions', [])} + os.makedirs(os.path.dirname(db_path) or '.', exist_ok=True) conn = sqlite3.connect(db_path, timeout=60.0) @@ -367,7 +370,7 @@ try: elif 'tmux_sessions' not in d: d['tmux_sessions'] = [] - old_terminals = get_terminal_set(d) + old_sessions = get_all_sessions_status(d) old_roles = {s.get('name'): s.get('role') for s in db_sessions if s.get('role')} # --- caller mutation (module scope: sees d, yaml, os, glob, subprocess) --- @@ -400,13 +403,12 @@ try: else: conn.execute('DELETE FROM sessions') - new_terminals = get_terminal_set(d) + new_sessions = get_all_sessions_status(d) conn.commit() - # Write to YAML ONLY when a session transitions to a finished state - # (Moved after conn.commit() per Claude's feedback) - if new_terminals != old_terminals: + # Write to YAML when sessions status or session list changes (e.g. create/stop/resume) + if new_sessions != old_sessions: if os.path.exists(yaml_path): try: shutil.copy2(yaml_path, yaml_path + '.bak') @@ -509,7 +511,7 @@ def emit(u): sessions = [] try: if os.path.exists(db_path): - conn = sqlite3.connect(db_path, timeout=10.0) + conn = sqlite3.connect(db_path, timeout=60.0) has_sessions_table = False try: cursor = conn.execute('SELECT data FROM sessions WHERE pane_cwd=?', (ws,)) @@ -621,7 +623,7 @@ elif agent == 'cline': ai = {} try: if os.path.exists(db_path): - conn = sqlite3.connect(db_path, timeout=10.0) + conn = sqlite3.connect(db_path, timeout=60.0) row = conn.execute('SELECT data FROM state WHERE id=1').fetchone() if row: ai = json.loads(row[0]).get('agent_identities', {}) @@ -687,7 +689,7 @@ yaml_path = os.environ['YAML_PATH'] db_path = os.path.splitext(yaml_path)[0] + '.db' try: if os.path.exists(db_path): - conn = sqlite3.connect(db_path, timeout=10.0) + conn = sqlite3.connect(db_path, timeout=60.0) has_sessions_table = False try: row = conn.execute('SELECT status, data FROM sessions WHERE name=?', (name,)).fetchone() diff --git a/.agents/skills/multi-agent-mux-create/scripts/create_session.sh b/.agents/skills/multi-agent-mux-create/scripts/create_session.sh index ebac352..cdcccf2 100755 --- a/.agents/skills/multi-agent-mux-create/scripts/create_session.sh +++ b/.agents/skills/multi-agent-mux-create/scripts/create_session.sh @@ -145,6 +145,16 @@ fi spawn +# Trap for rolling back/cleaning up tmux session if script exits due to error +cleanup_tmux_on_error() { + local exit_code=$? + if [ $exit_code -ne 0 ]; then + echo "⚠️ Error occurred during initialization. Rolling back and killing tmux session '$SESSION_NAME'..." >&2 + _tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true + fi +} +trap cleanup_tmux_on_error EXIT + # TUI 준비 대기 wait_for_tui_ready "$SESSION_NAME" "$AGENT" @@ -333,6 +343,8 @@ Task: $SUBMIT_JOB_PROMPT" WD_PID=$(start_watchdog "$DELEGATE_JOB_ID" "$WORKSPACE") echo "watchdog PID: $WD_PID" fi +# Clear cleanup trap as registration was fully successful +trap - EXIT echo "agent-sessions.yaml updated" echo if [ -n "${TMUX_SERVER_NAME:-}" ] && [ "$TMUX_SERVER_NAME" != "default" ]; then diff --git a/.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh b/.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh index 7b9b917..f4a9e07 100755 --- a/.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh +++ b/.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh @@ -301,7 +301,7 @@ except NameError: d = {} try: if os.path.exists(db_path): - conn = sqlite3.connect(db_path, timeout=10.0) + conn = sqlite3.connect(db_path, timeout=60.0) row = conn.execute('SELECT data FROM state WHERE id=1').fetchone() if row: d = json.loads(row[0]) diff --git a/.agents/skills/multi-agent-mux-resume/scripts/update_yaml_resumed.sh b/.agents/skills/multi-agent-mux-resume/scripts/update_yaml_resumed.sh index 01d5a2d..079532d 100755 --- a/.agents/skills/multi-agent-mux-resume/scripts/update_yaml_resumed.sh +++ b/.agents/skills/multi-agent-mux-resume/scripts/update_yaml_resumed.sh @@ -65,7 +65,7 @@ db_path = os.path.splitext(yaml_path)[0] + '.db' d = {} try: if os.path.exists(db_path): - conn = sqlite3.connect(db_path, timeout=10.0) + conn = sqlite3.connect(db_path, timeout=60.0) try: row = conn.execute('SELECT data FROM sessions WHERE name=?', (name,)).fetchone() if row: diff --git a/.agents/skills/multi-agent-mux-status/scripts/status.sh b/.agents/skills/multi-agent-mux-status/scripts/status.sh index 66a51d4..1a17a53 100755 --- a/.agents/skills/multi-agent-mux-status/scripts/status.sh +++ b/.agents/skills/multi-agent-mux-status/scripts/status.sh @@ -42,7 +42,7 @@ d = {} import sqlite3 try: if os.path.exists(db_path): - conn = sqlite3.connect(db_path, timeout=10.0) + conn = sqlite3.connect(db_path, timeout=60.0) row = conn.execute('SELECT data FROM state WHERE id=1').fetchone() if row: d = json.loads(row[0]) diff --git a/.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh b/.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh index 0514a8b..0789f5e 100755 --- a/.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh +++ b/.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh @@ -91,7 +91,7 @@ db_path = os.path.splitext(yaml_path)[0] + '.db' d = {} try: if os.path.exists(db_path): - conn = sqlite3.connect(db_path, timeout=10.0) + conn = sqlite3.connect(db_path, timeout=60.0) try: row = conn.execute('SELECT data FROM sessions WHERE name=?', (name,)).fetchone() if row: