mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-12 21:56:21 +00:00
feat(i18n): deploy libretranslate into the i18n runner before translating
server() now resolves a translation endpoint in three steps: use the running service, rebuild when the host has a GPU but no accelerated deploy left its stamp, otherwise deploy. A plain run therefore costs nothing, and the rebuild fires once, on the move from a CPU-built container to an accelerated one. deploy() brings the runner up, waits for State.Running and deploys the role inside it. The exec steps address `docker compose exec i18n` directly: cli.administration.deploy.development exec hardcodes the `infinito` service (compose.py:261), so every deploy through it silently ran in the main container, where mailu already holds port 25 and postfix cannot start. check=True stops a failing step instead of carrying on against the wrong target. The deploy router writes its pid to build/deploy.pid, which survives the exec into the subscripts, and deploying() refuses a translation while that process lives. The running deploy is left untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
bb1dbaa022
commit
a0a24e2c0e
5 files changed
+286
-7
No files matched your search
@@ -1,9 +1,50 @@
|
||||
import os
|
||||
import subprocess
|
||||
import unittest
|
||||
import unittest.mock as mock
|
||||
import urllib.error
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
from utils.i18n.libretranslate import LibreTranslate, accelerated
|
||||
from utils.i18n.libretranslate import (
|
||||
LibreTranslate,
|
||||
accelerated,
|
||||
deploying,
|
||||
server,
|
||||
)
|
||||
|
||||
|
||||
class TestParallelDeployIsRefused(unittest.TestCase):
|
||||
def test_a_running_deploy_stops_the_translation(self) -> None:
|
||||
with (
|
||||
mock.patch("utils.i18n.libretranslate.deploying", return_value=True),
|
||||
mock.patch("utils.i18n.libretranslate.deploy") as started,
|
||||
self.assertRaises(RuntimeError),
|
||||
server(Path("/repo"), ["de"], 1),
|
||||
):
|
||||
pass
|
||||
started.assert_not_called()
|
||||
|
||||
def test_a_live_router_pid_reports_a_deploy(self) -> None:
|
||||
self.assertTrue(deploying(self._root_holding(os.getpid())))
|
||||
|
||||
def test_a_stale_pid_file_reports_no_deploy(self) -> None:
|
||||
root = self._root_holding(4242)
|
||||
with mock.patch("os.kill", side_effect=ProcessLookupError):
|
||||
self.assertFalse(deploying(root))
|
||||
|
||||
def test_a_missing_pid_file_reports_no_deploy(self) -> None:
|
||||
self.assertFalse(deploying(Path(self._tmp.name)))
|
||||
|
||||
def _root_holding(self, pid: int) -> Path:
|
||||
root = Path(self._tmp.name)
|
||||
(root / "build").mkdir(exist_ok=True)
|
||||
(root / "build" / "deploy.pid").write_text(str(pid))
|
||||
return root
|
||||
|
||||
def setUp(self) -> None:
|
||||
self._tmp = TemporaryDirectory()
|
||||
self.addCleanup(self._tmp.cleanup)
|
||||
|
||||
|
||||
class TestTranslateFailures(unittest.TestCase):
|
||||
|
||||
Reference in new issue
Block a user