diff --git a/gui/ninepconnection.cpp b/gui/ninepconnection.cpp index 76d3183..794bd75 100644 --- a/gui/ninepconnection.cpp +++ b/gui/ninepconnection.cpp @@ -12,12 +12,14 @@ NinePConnection::~NinePConnection() stop(); } -void NinePConnection::start(const QString &program, const QStringList &args, int retryMs, bool probe) +void NinePConnection::start(const QString &program, const QStringList &args, int retryMs, bool probe, int maxRetries) { m_program = program; m_args = args; m_retryMs = retryMs; m_probe = probe; + m_maxRetries = maxRetries; + m_retryCount = 0; m_stopRequested = false; m_openMarkerSeen = false; m_retryTimer.stop(); @@ -91,17 +93,21 @@ void NinePConnection::onFinished(int exitCode, QProcess::ExitStatus) if (!m_process) return; m_process->deleteLater(); m_process = nullptr; + // Successful probe that was connected: schedule re-probe (reset retry count). if (m_probe && m_state == Connected && m_openMarkerSeen && exitCode == 0 && !m_stopRequested) { + m_retryCount = 0; if (m_retryMs > 0) m_retryTimer.start(m_retryMs); else startProcess(); // immediate re-probe return; } - if (m_stopRequested || m_retryMs <= 0) { + // No retry configured, or stop requested, or max retries exceeded. + if (m_stopRequested || m_retryMs <= 0 || (m_maxRetries > 0 && m_retryCount >= m_maxRetries)) { setState(Disconnected); return; } + ++m_retryCount; setState(RetryWait); m_retryTimer.start(m_retryMs); } diff --git a/gui/ninepconnection.h b/gui/ninepconnection.h index 18df1f7..5d2621d 100644 --- a/gui/ninepconnection.h +++ b/gui/ninepconnection.h @@ -16,7 +16,7 @@ public: explicit NinePConnection(QObject *parent = nullptr); ~NinePConnection() override; - void start(const QString &program, const QStringList &args, int retryMs = 4000, bool probe = false); + void start(const QString &program, const QStringList &args, int retryMs = 4000, bool probe = false, int maxRetries = 0); void stop(); State state() const { return m_state; } @@ -47,6 +47,8 @@ private: int m_retryMs = 4000; bool m_probe = false; bool m_openMarkerSeen = false; + int m_maxRetries = 0; // 0 = unlimited + int m_retryCount = 0; }; #endif // NINEPCONNECTION_H diff --git a/gui/ollie9pclient.cpp b/gui/ollie9pclient.cpp index 4efcb22..ee315fa 100644 --- a/gui/ollie9pclient.cpp +++ b/gui/ollie9pclient.cpp @@ -254,11 +254,10 @@ void Ollie9pClient::reconcileAgentConnections() // rather than showing a transient red indicator. refreshSessions(); }); - // No retry — reconcileAgentConnections is the authority for - // connection lifecycle. If the agent is still alive after refresh, - // reconcile will create a new connection. + // Retry with backoff (5s, max 3 retries) to avoid hammering the server + // when the connection file exists but returns an error (e.g., toolsConn nil). connection->start(ollie9pBin(), {"-a", serverAddr(), "read", "--open-marker", - "session/" + sid + "/agent/" + aid + "/connection"}, 0, true); + "session/" + sid + "/agent/" + aid + "/connection"}, 5000, true, 3); } } for (auto it = m_agentConnections.begin(); it != m_agentConnections.end();) {