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>
This commit is contained in:
@@ -54,6 +54,9 @@ class JobManager:
|
|||||||
def remove_finished(self) -> None:
|
def remove_finished(self) -> None:
|
||||||
self._jobs = {k: v for k, v in self._jobs.items() if v.status == "running"}
|
self._jobs = {k: v for k, v in self._jobs.items() if v.status == "running"}
|
||||||
|
|
||||||
|
def start_job(self, app, job: Job, *cli_args: str) -> None:
|
||||||
|
asyncio.create_task(self.run_job(app, job, *cli_args))
|
||||||
|
|
||||||
async def run_job(self, app, job: Job, *cli_args: str) -> int:
|
async def run_job(self, app, job: Job, *cli_args: str) -> int:
|
||||||
proc = await start_cli_process(*cli_args)
|
proc = await start_cli_process(*cli_args)
|
||||||
job._proc = proc
|
job._proc = proc
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ from textual.app import ComposeResult
|
|||||||
from textual.screen import Screen
|
from textual.screen import Screen
|
||||||
from textual.widgets import Header, Footer, Static, Button, Select
|
from textual.widgets import Header, Footer, Static, Button, Select
|
||||||
from textual.containers import Vertical, Horizontal
|
from textual.containers import Vertical, Horizontal
|
||||||
from textual import work
|
|
||||||
|
|
||||||
from tui.config import list_conf_dir, has_targets, has_remotes
|
from tui.config import list_conf_dir, has_targets, has_remotes
|
||||||
from tui.jobs import job_manager
|
from tui.jobs import job_manager
|
||||||
from tui.widgets import ConfirmDialog
|
from tui.widgets import ConfirmDialog
|
||||||
@@ -65,20 +63,18 @@ class BackupScreen(Screen):
|
|||||||
callback=lambda ok: self._do_backup_all() if ok else None,
|
callback=lambda ok: self._do_backup_all() if ok else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
@work
|
def _do_backup(self, target: str, remote: str) -> None:
|
||||||
async def _do_backup(self, target: str, remote: str) -> None:
|
|
||||||
job = job_manager.create_job("backup", f"Backup: {target}")
|
job = job_manager.create_job("backup", f"Backup: {target}")
|
||||||
args = ["backup", f"--target={target}"]
|
args = ["backup", f"--target={target}"]
|
||||||
if remote:
|
if remote:
|
||||||
args.append(f"--remote={remote}")
|
args.append(f"--remote={remote}")
|
||||||
|
job_manager.start_job(self.app, job, *args)
|
||||||
self.app.switch_screen("running_tasks")
|
self.app.switch_screen("running_tasks")
|
||||||
await job_manager.run_job(self.app, job, *args)
|
|
||||||
|
|
||||||
@work
|
def _do_backup_all(self) -> None:
|
||||||
async def _do_backup_all(self) -> None:
|
|
||||||
job = job_manager.create_job("backup", "Backup All Targets")
|
job = job_manager.create_job("backup", "Backup All Targets")
|
||||||
|
job_manager.start_job(self.app, job, "backup", "--all")
|
||||||
self.app.switch_screen("running_tasks")
|
self.app.switch_screen("running_tasks")
|
||||||
await job_manager.run_job(self.app, job, "backup", "--all")
|
|
||||||
|
|
||||||
def action_go_back(self) -> None:
|
def action_go_back(self) -> None:
|
||||||
self.app.pop_screen()
|
self.app.pop_screen()
|
||||||
|
|||||||
@@ -143,16 +143,15 @@ class RestoreScreen(Screen):
|
|||||||
callback=lambda ok: self._do_restore(target, remote, snapshot, dest, skip_mysql) if ok else None,
|
callback=lambda ok: self._do_restore(target, remote, snapshot, dest, skip_mysql) if ok else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
@work
|
def _do_restore(self, target: str, remote: str, snapshot: str, dest: str, skip_mysql: bool = False) -> None:
|
||||||
async def _do_restore(self, target: str, remote: str, snapshot: str, dest: str, skip_mysql: bool = False) -> None:
|
|
||||||
job = job_manager.create_job("restore", f"Restore: {target}")
|
job = job_manager.create_job("restore", f"Restore: {target}")
|
||||||
args = ["restore", f"--target={target}", f"--remote={remote}", f"--snapshot={snapshot}"]
|
args = ["restore", f"--target={target}", f"--remote={remote}", f"--snapshot={snapshot}"]
|
||||||
if dest:
|
if dest:
|
||||||
args.append(f"--dest={dest}")
|
args.append(f"--dest={dest}")
|
||||||
if skip_mysql:
|
if skip_mysql:
|
||||||
args.append("--skip-mysql")
|
args.append("--skip-mysql")
|
||||||
|
job_manager.start_job(self.app, job, *args)
|
||||||
self.app.switch_screen("running_tasks")
|
self.app.switch_screen("running_tasks")
|
||||||
await job_manager.run_job(self.app, job, *args)
|
|
||||||
|
|
||||||
def action_go_back(self) -> None:
|
def action_go_back(self) -> None:
|
||||||
self.app.pop_screen()
|
self.app.pop_screen()
|
||||||
|
|||||||
Reference in New Issue
Block a user