Commit Graph

10 Commits

Author SHA1 Message Date
shuki
58819abcd4 Persist finished jobs in registry and fix reconnection bugs
- Save finished jobs to registry (24h TTL) so they survive TUI restart
- Fix PermissionError in PID check incorrectly marking alive processes as dead
- Handle CancelledError explicitly to preserve running status on TUI exit
- Tail log files for reconnected running jobs instead of showing stale output
- Detect actual return code from log content; show "?" for unknown status

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:06:48 +02:00
shuki
8fec087987 Write job output to file instead of pipe to survive TUI exit
The subprocess stdout was a pipe to the TUI. When the TUI exited, the
pipe broke (SIGPIPE) and killed the backup process. Now the subprocess
writes to a log file in WORK_DIR, and the TUI tails it for live
display. When the TUI exits, the subprocess keeps running because it
writes to a file, not a pipe. On restart, the log file is loaded to
show output for reconnected or finished background jobs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:50:09 +02:00
shuki
a08cf9911c Show background jobs that finished while TUI was closed
Previously _load_registry silently dropped dead PIDs, so jobs that
completed in the background were invisible on restart. Now dead PIDs
are loaded as 'success' status so the user sees they completed. The
registry is cleaned up after loading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:46:47 +02:00
shuki
ba93a74f8e Persist running jobs to registry for TUI reconnection
Jobs are now saved to gniza-jobs.json in WORK_DIR when they start and
finish. On TUI restart, the registry is loaded and PIDs are checked —
still-running jobs appear in the Running Tasks screen and can be
killed. Reconnected jobs are polled every second to detect completion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:27:37 +02:00
shuki
54c7b75cee Add debug output to kill_job to diagnose kill failure
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:20:53 +02:00
shuki
0110b00b67 Decouple job lifecycle from screen workers
Jobs were tied to screen @work tasks, so switch_screen cancelled the
worker and lost the process reference. Now start_job uses
asyncio.create_task so jobs survive screen changes and can be killed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:18:39 +02:00
shuki
6a0389f437 Use SIGKILL and os.getpgid for reliable job killing
SIGTERM was being ignored by child processes. Use SIGKILL via the
actual process group ID, with proc.kill() as fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:16:09 +02:00
shuki
c96930f3ff Kill entire process group when stopping a job
Start CLI subprocesses in their own session so SIGTERM via
os.killpg reaches child processes (rsync, etc.) not just the shell.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:11:37 +02:00
shuki
2379c2fdeb Add Kill Job button to Running Tasks screen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:10:19 +02:00
shuki
8a83812584 Add background jobs system with Running Tasks screen
Backup and restore operations now run as background jobs instead of
blocking modal screens. Users can navigate away and check progress
from a dedicated Running Tasks screen. OperationLog supports attaching
to running jobs with live output polling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:07:34 +02:00