fix(gui): add retry backoff for agent connections
Agent connections were using retryMs=0, causing a tight loop when the /connection file read failed (e.g., toolsConn nil). The loop was: connection fails → disconnected signal → refreshSessions → reconcileAgentConnections → new connection → fails immediately → repeat Fix by: - Add maxRetries parameter to NinePConnection::start() - Use 5s retry interval with max 3 retries for agent connections - Reset retry count on successful connection
This commit is contained in:
parent
8a0a5e6ff9
commit
21baea8691
|
|
@ -12,12 +12,14 @@ NinePConnection::~NinePConnection()
|
||||||
stop();
|
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_program = program;
|
||||||
m_args = args;
|
m_args = args;
|
||||||
m_retryMs = retryMs;
|
m_retryMs = retryMs;
|
||||||
m_probe = probe;
|
m_probe = probe;
|
||||||
|
m_maxRetries = maxRetries;
|
||||||
|
m_retryCount = 0;
|
||||||
m_stopRequested = false;
|
m_stopRequested = false;
|
||||||
m_openMarkerSeen = false;
|
m_openMarkerSeen = false;
|
||||||
m_retryTimer.stop();
|
m_retryTimer.stop();
|
||||||
|
|
@ -91,17 +93,21 @@ void NinePConnection::onFinished(int exitCode, QProcess::ExitStatus)
|
||||||
if (!m_process) return;
|
if (!m_process) return;
|
||||||
m_process->deleteLater();
|
m_process->deleteLater();
|
||||||
m_process = nullptr;
|
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) {
|
if (m_probe && m_state == Connected && m_openMarkerSeen && exitCode == 0 && !m_stopRequested) {
|
||||||
|
m_retryCount = 0;
|
||||||
if (m_retryMs > 0)
|
if (m_retryMs > 0)
|
||||||
m_retryTimer.start(m_retryMs);
|
m_retryTimer.start(m_retryMs);
|
||||||
else
|
else
|
||||||
startProcess(); // immediate re-probe
|
startProcess(); // immediate re-probe
|
||||||
return;
|
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);
|
setState(Disconnected);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
++m_retryCount;
|
||||||
setState(RetryWait);
|
setState(RetryWait);
|
||||||
m_retryTimer.start(m_retryMs);
|
m_retryTimer.start(m_retryMs);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ public:
|
||||||
explicit NinePConnection(QObject *parent = nullptr);
|
explicit NinePConnection(QObject *parent = nullptr);
|
||||||
~NinePConnection() override;
|
~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();
|
void stop();
|
||||||
State state() const { return m_state; }
|
State state() const { return m_state; }
|
||||||
|
|
||||||
|
|
@ -47,6 +47,8 @@ private:
|
||||||
int m_retryMs = 4000;
|
int m_retryMs = 4000;
|
||||||
bool m_probe = false;
|
bool m_probe = false;
|
||||||
bool m_openMarkerSeen = false;
|
bool m_openMarkerSeen = false;
|
||||||
|
int m_maxRetries = 0; // 0 = unlimited
|
||||||
|
int m_retryCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NINEPCONNECTION_H
|
#endif // NINEPCONNECTION_H
|
||||||
|
|
|
||||||
|
|
@ -254,11 +254,10 @@ void Ollie9pClient::reconcileAgentConnections()
|
||||||
// rather than showing a transient red indicator.
|
// rather than showing a transient red indicator.
|
||||||
refreshSessions();
|
refreshSessions();
|
||||||
});
|
});
|
||||||
// No retry — reconcileAgentConnections is the authority for
|
// Retry with backoff (5s, max 3 retries) to avoid hammering the server
|
||||||
// connection lifecycle. If the agent is still alive after refresh,
|
// when the connection file exists but returns an error (e.g., toolsConn nil).
|
||||||
// reconcile will create a new connection.
|
|
||||||
connection->start(ollie9pBin(), {"-a", serverAddr(), "read", "--open-marker",
|
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();) {
|
for (auto it = m_agentConnections.begin(); it != m_agentConnections.end();) {
|
||||||
|
|
|
||||||
Reference in New Issue