Fix mita RPC socket path and rate-limit heal recovery.

This commit is contained in:
orohi
2026-08-03 12:18:53 +03:00
parent c0ce490a15
commit bf1c6761fd
2 changed files with 45 additions and 36 deletions
+1 -1
View File
@@ -103,7 +103,7 @@ else:
application_path = os.path.dirname(__file__) application_path = os.path.dirname(__file__)
DATA_FILE = os.path.join(application_path, 'data.json') # legacy JSON; used only for one-shot import / export DATA_FILE = os.path.join(application_path, 'data.json') # legacy JSON; used only for one-shot import / export
CURRENT_VERSION = "v2.6.8" CURRENT_VERSION = "v2.6.9"
RELEASES_REPO_URL = repo_url() RELEASES_REPO_URL = repo_url()
RELEASES_API_LATEST = api_latest_url() RELEASES_API_LATEST = api_latest_url()
BIN_DIR = os.environ.get('TUNNEL_BIN_DIR', os.path.join(application_path, 'bin')) BIN_DIR = os.environ.get('TUNNEL_BIN_DIR', os.path.join(application_path, 'bin'))
+32 -23
View File
@@ -21,7 +21,9 @@ logger = logging.getLogger(__name__)
MIERU_RELEASE = '3.28.0' MIERU_RELEASE = '3.28.0'
GITHUB_RELEASE = f'https://github.com/enfein/mieru/releases/download/v{MIERU_RELEASE}' GITHUB_RELEASE = f'https://github.com/enfein/mieru/releases/download/v{MIERU_RELEASE}'
MITA_SOCK = '/var/run/mita.sock' # Official mita UDS (v3.x). Older docs sometimes mention /var/run/mita.sock.
MITA_SOCK = '/var/run/mita/mita.sock'
MITA_SOCK_LEGACY = '/var/run/mita.sock'
# Official package persists applied config here. If this file has portBindings # Official package persists applied config here. If this file has portBindings
# but no users, `mita run` (systemd) auto-starts the proxy and FATAL-exits # but no users, `mita run` (systemd) auto-starts the proxy and FATAL-exits
# with "socks5 server listening failed: no user found", crashing the daemon. # with "socks5 server listening failed: no user found", crashing the daemon.
@@ -246,10 +248,14 @@ class MieruManager:
self.ssh.run_sudo_command( self.ssh.run_sudo_command(
f"systemctl stop {self.SERVICE_NAME} 2>/dev/null || true; " f"systemctl stop {self.SERVICE_NAME} 2>/dev/null || true; "
f"systemctl reset-failed {self.SERVICE_NAME} 2>/dev/null || true; " f"systemctl reset-failed {self.SERVICE_NAME} 2>/dev/null || true; "
f"rm -f {_q(MITA_SOCK)} /var/run/mita/*.sock " f"rm -f {_q(MITA_SOCK)} {_q(MITA_SOCK_LEGACY)} /var/run/mita/*.sock "
f"{_q(MITA_CONFIG_PB)} {_q(MITA_CONFIG_JSON)} 2>/dev/null || true", f"{_q(MITA_CONFIG_PB)} {_q(MITA_CONFIG_JSON)} 2>/dev/null || true; "
f"mkdir -p /var/run/mita /etc/mita 2>/dev/null || true",
timeout=60, timeout=60,
) )
# systemd StartLimitBurst: wait out "Start request repeated too quickly".
time.sleep(6)
clients = self._ensure_bootstrap_clients(self._read_clients()) clients = self._ensure_bootstrap_clients(self._read_clients())
self._write_clients(clients) self._write_clients(clients)
meta = self._read_metadata() meta = self._read_metadata()
@@ -258,17 +264,26 @@ class MieruManager:
self._write_file(self.config_path, json.dumps(config, indent=2)) self._write_file(self.config_path, json.dumps(config, indent=2))
self.ssh.run_sudo_command( self.ssh.run_sudo_command(
f"systemctl reset-failed {self.SERVICE_NAME} 2>/dev/null || true; "
f"systemctl start {self.SERVICE_NAME}", f"systemctl start {self.SERVICE_NAME}",
timeout=60, timeout=60,
) )
if not self._wait_for_rpc(timeout=60):
# Second attempt after another rate-limit window.
self.ssh.run_sudo_command(
f"systemctl reset-failed {self.SERVICE_NAME} 2>/dev/null || true; "
f"systemctl restart {self.SERVICE_NAME}",
timeout=60,
)
time.sleep(3)
if not self._wait_for_rpc(timeout=45): if not self._wait_for_rpc(timeout=45):
journal, _, _ = self.ssh.run_sudo_command( journal, _, _ = self.ssh.run_sudo_command(
f"journalctl -u {self.SERVICE_NAME} -n 40 --no-pager 2>&1", f"journalctl -u {self.SERVICE_NAME} -n 50 --no-pager 2>&1",
timeout=30, timeout=30,
) )
raise RuntimeError( raise RuntimeError(
'mita daemon still not ready after heal. ' 'mita daemon still not ready after heal. '
f'journal: {(journal or "").strip()[-500:]}' f'journal: {(journal or "").strip()[-600:]}'
) )
out, err, code = self._mita_cli( out, err, code = self._mita_cli(
['apply', 'config', _q(self.config_path)], ['apply', 'config', _q(self.config_path)],
@@ -284,7 +299,8 @@ class MieruManager:
def _ensure_daemon(self, log=None): def _ensure_daemon(self, log=None):
"""Ensure mita systemd unit is up and RPC socket answers.""" """Ensure mita systemd unit is up and RPC socket answers."""
self.ssh.run_sudo_command( self.ssh.run_sudo_command(
f"systemctl enable {self.SERVICE_NAME} 2>/dev/null || true", f"systemctl enable {self.SERVICE_NAME} 2>/dev/null || true; "
f"mkdir -p /var/run/mita /etc/mita 2>/dev/null || true",
timeout=30, timeout=30,
) )
# Official package expects the operating user in group `mita`. # Official package expects the operating user in group `mita`.
@@ -308,29 +324,19 @@ class MieruManager:
timeout=60, timeout=60,
) )
if not self._wait_for_rpc(timeout=45): if not self._wait_for_rpc(timeout=45):
# Crash loop / stale socket — wipe broken store and recover. # Crash loop / wrong socket / rate-limit — wipe store and recover.
if self._daemon_needs_heal():
self._heal_mita_store(log)
else:
self.ssh.run_sudo_command(
f"systemctl stop {self.SERVICE_NAME} 2>/dev/null || true; "
f"rm -f {_q(MITA_SOCK)} /var/run/mita/*.sock 2>/dev/null || true; "
f"systemctl start {self.SERVICE_NAME}",
timeout=60,
)
if not self._wait_for_rpc(timeout=45):
# Last resort: heal even if journal didn't match yet.
self._heal_mita_store(log) self._heal_mita_store(log)
if log is not None: if log is not None:
log.append('mita daemon is active') log.append('mita daemon is active')
def _wait_for_rpc(self, timeout=30): def _wait_for_rpc(self, timeout=30):
deadline = time.time() + timeout deadline = time.time() + timeout
while time.time() < deadline: sock_check = (
sock_out, _, sock_code = self.ssh.run_sudo_command( f"(test -S {_q(MITA_SOCK)} || test -S {_q(MITA_SOCK_LEGACY)}) && echo ok"
f"test -S {_q(MITA_SOCK)} && echo ok"
) )
if sock_code == 0 and 'ok' in (sock_out or ''): while time.time() < deadline:
# Prefer CLI status: if it answers IDLE/RUNNING, RPC is up
# regardless of which sock path we expected.
status_out, _, status_code = self.ssh.run_sudo_command( status_out, _, status_code = self.ssh.run_sudo_command(
'mita status 2>&1', 'mita status 2>&1',
timeout=20, timeout=20,
@@ -338,7 +344,10 @@ class MieruManager:
text = (status_out or '').upper() text = (status_out or '').upper()
if status_code == 0 and ('IDLE' in text or 'RUNNING' in text): if status_code == 0 and ('IDLE' in text or 'RUNNING' in text):
return True return True
# Socket exists but CLI still races — brief pause. sock_out, _, sock_code = self.ssh.run_sudo_command(sock_check)
if sock_code == 0 and 'ok' in (sock_out or ''):
time.sleep(1)
continue
time.sleep(1.5) time.sleep(1.5)
return False return False