feat: backoff retry after number of retries

This commit is contained in:
sithlord48 2026-03-24 21:15:56 -04:00 committed by Chris Rizzitello
parent ebab0eb62e
commit 468c3b76de
12 changed files with 124 additions and 20 deletions

View file

@ -50,15 +50,16 @@ option=value
This section contains options used when in client mode.
It will begin with `[client]`
| Option | Valid Values | Description |
|:------------------|:------------------:|:-----------|
| languageSync | `true` or `false` | Sync to server language [default: true] |
| remoteHost | `IP` or `hostname` | The remote host(s) to connect to. Use a comma separated list when you want to try several hosts |
| yScrollScale | Double 0.1 - 10.0 | Vertical mouse scrolling will be scaled by this amount on the client [default: 1.0] |
| xScrollScale | Double 0.1 - 10.0 | Horizontal mouse scrolling will be scaled by this amount on the client [default: 1.0] |
| invertYScroll | `true` or `false` | Invert vertical scroll on this client [default: false] |
| invertXScroll | `true` or `false` | Invert horizontal scroll on this client [default: false] |
| xdpRestoreToken | UUID | Restore token provided by XDG portals |
| Option | Valid Values | Description |
|:--------------------------|:------------------:|:-----------|
| dynamicConnectionInterval | `true` or `false` | Use dynamic connection retry times based on number of previously failed attempts [default: false] |
| languageSync | `true` or `false` | Sync to server language [default: true] |
| remoteHost | `IP` or `hostname` | The remote host(s) to connect to. Use a comma separated list when you want to try several hosts |
| yScrollScale | Double 0.1 - 10.0 | Vertical mouse scrolling will be scaled by this amount on the client [default: 1.0] |
| xScrollScale | Double 0.1 - 10.0 | Horizontal mouse scrolling will be scaled by this amount on the client [default: 1.0] |
| invertYScroll | `true` or `false` | Invert vertical scroll on this client [default: false] |
| invertXScroll | `true` or `false` | Invert horizontal scroll on this client [default: false] |
| xdpRestoreToken | UUID | Restore token provided by XDG portals |
### Core

View file

@ -34,6 +34,7 @@ public:
struct Client
{
inline static const auto DynamicConnectionRetry = QStringLiteral("client/dynamicConnectionInterval");
inline static const auto InvertYScroll = QStringLiteral("client/invertYScroll");
inline static const auto InvertXScroll = QStringLiteral("client/invertXScroll");
inline static const auto YScrollScale = QStringLiteral("client/yScrollScale");
@ -198,7 +199,8 @@ private:
};
inline static const QStringList m_validKeys = {
Settings::Client::InvertYScroll
Settings::Client::DynamicConnectionRetry
, Settings::Client::InvertYScroll
, Settings::Client::InvertXScroll
, Settings::Client::LanguageSync
, Settings::Client::RemoteHost
@ -260,6 +262,7 @@ private:
, Settings::Core::UseWlClipboard
, Settings::Core::EnableEnterCommand
, Settings::Core::EnableExitCommand
, Settings::Client::DynamicConnectionRetry
, Settings::Server::ExternalConfig
, Settings::Client::InvertYScroll
, Settings::Client::InvertXScroll

View file

@ -45,8 +45,6 @@
#include <memory>
constexpr static auto s_retryTime = 1.0;
ClientApp::ClientApp(IEventQueue *events, const QString &processName) : App(events, processName)
{
// do nothing
@ -164,8 +162,8 @@ void ClientApp::handleClientRestart(const Event &, EventQueueTimer *timer)
void ClientApp::scheduleClientRestart(double retryTime)
{
// install a timer and handler to retry later
LOG_DEBUG("retry in %.0f seconds", retryTime);
// install a timer and handler to retry later
EventQueueTimer *timer = getEvents()->newOneShotTimer(retryTime, nullptr);
getEvents()->addHandler(EventTypes::Timer, timer, [this, timer](const auto &e) { handleClientRestart(e, timer); });
}
@ -186,7 +184,7 @@ void ClientApp::handleClientFailed(const Event &e)
LOG_WARN("failed to connect to server=%s, trying next resolved address", info->m_what.c_str());
if (!m_suspended) {
scheduleClientRestart(s_retryTime);
scheduleClientRestart(retryTime());
}
} else {
// All resolved addresses exhausted, try next server in list
@ -200,7 +198,7 @@ void ClientApp::handleClientFailed(const Event &e)
std::unique_ptr<Client::FailInfo> info(static_cast<Client::FailInfo *>(e.getData()));
LOG_WARN("failed to connect to server=%s, trying next server in list", info->m_what.c_str());
if (!m_suspended) {
scheduleClientRestart(s_retryTime);
scheduleClientRestart(retryTime());
}
}
}
@ -216,16 +214,18 @@ void ClientApp::handleClientRefused(const Event &e)
} else {
LOG_WARN("failed to connect to server: %s", info->m_what.c_str());
if (!m_suspended) {
scheduleClientRestart(s_retryTime);
m_retryCount++;
scheduleClientRestart(retryTime());
}
}
}
void ClientApp::handleClientDisconnected()
{
m_retryCount = 0;
LOG_IPC("disconnected from server");
if (!m_suspended) {
scheduleClientRestart(s_retryTime);
scheduleClientRestart(retryTime());
}
}
@ -299,7 +299,7 @@ bool ClientApp::startClient()
return false;
}
scheduleClientRestart(s_retryTime);
scheduleClientRestart(retryTime());
return true;
}
@ -393,3 +393,20 @@ ISocketFactory *ClientApp::getSocketFactory() const
{
return new TCPSocketFactory(getEvents(), getSocketMultiplexer());
}
double ClientApp::retryTime() const
{
if (!Settings::value(Settings::Client::DynamicConnectionRetry).toBool() || m_retryCount < 300) // 5 minutes
return 1;
if (m_retryCount < 360) // 5 minutes
return 5;
if (m_retryCount < 390) // 5 minutes
return 10;
if (m_retryCount < 410) // 10 minutes
return 30;
if (m_retryCount < 420) // 10 minutes
return 60;
if (m_retryCount < 430) // 20 minutes
return 120;
return 300;
}

View file

@ -78,6 +78,12 @@ public:
return (ClientApp &)App::instance();
}
/**
* @brief retryTime
* @return next retry time based on number of current retries
*/
double retryTime() const;
private:
ISocketFactory *getSocketFactory() const;
NetworkAddress &getCurrentServerAddress();
@ -89,4 +95,5 @@ private:
QList<NetworkAddress> m_serverAddresses;
size_t m_currentServerIndex = 0;
size_t m_lastServerAddressIndex = 0;
uint m_retryCount = 0;
};

View file

@ -52,6 +52,9 @@ void ClientConfigDialog::initConnections() const
&ClientConfigDialog::resetToDefault
);
connect(
ui->cbDynamicConnectTime, &QCheckBox::checkStateChanged, this, &ClientConfigDialog::setButtonBoxEnabledButtons
);
connect(ui->cbLanguageSync, &QCheckBox::checkStateChanged, this, &ClientConfigDialog::setButtonBoxEnabledButtons);
connect(ui->cbYScrollInvert, &QCheckBox::checkStateChanged, this, &ClientConfigDialog::setButtonBoxEnabledButtons);
connect(ui->sbYScrollScale, &QDoubleSpinBox::valueChanged, this, &ClientConfigDialog::setButtonBoxEnabledButtons);
@ -61,7 +64,9 @@ void ClientConfigDialog::initConnections() const
bool ClientConfigDialog::isModified() const
{
return (ui->cbLanguageSync->isChecked() != Settings::value(Settings::Client::LanguageSync).toBool()) ||
return (ui->cbDynamicConnectTime->isChecked() != Settings::value(Settings::Client::DynamicConnectionRetry).toBool()
) ||
(ui->cbLanguageSync->isChecked() != Settings::value(Settings::Client::LanguageSync).toBool()) ||
(ui->cbYScrollInvert->isChecked() != Settings::value(Settings::Client::InvertYScroll).toBool()) ||
(ui->sbYScrollScale->value() != Settings::value(Settings::Client::YScrollScale).toDouble()) ||
(ui->cbXScrollInvert->isChecked() != Settings::value(Settings::Client::InvertXScroll).toBool()) ||
@ -70,7 +75,9 @@ bool ClientConfigDialog::isModified() const
bool ClientConfigDialog::isDefault() const
{
return (ui->cbLanguageSync->isChecked() == Settings::defaultValue(Settings::Client::LanguageSync).toBool()) &&
return (ui->cbDynamicConnectTime->isChecked() ==
Settings::defaultValue(Settings::Client::DynamicConnectionRetry).toBool()) &&
(ui->cbLanguageSync->isChecked() == Settings::defaultValue(Settings::Client::LanguageSync).toBool()) &&
(ui->cbYScrollInvert->isChecked() == Settings::defaultValue(Settings::Client::InvertYScroll).toBool()) &&
(ui->sbYScrollScale->value() == Settings::defaultValue(Settings::Client::YScrollScale).toDouble()) &&
(ui->cbXScrollInvert->isChecked() == Settings::defaultValue(Settings::Client::InvertXScroll).toBool()) &&
@ -87,6 +94,7 @@ void ClientConfigDialog::setButtonBoxEnabledButtons() const
void ClientConfigDialog::load()
{
ui->cbDynamicConnectTime->setChecked(Settings::value(Settings::Client::DynamicConnectionRetry).toBool());
ui->cbLanguageSync->setChecked(Settings::value(Settings::Client::LanguageSync).toBool());
ui->cbYScrollInvert->setChecked(Settings::value(Settings::Client::InvertYScroll).toBool());
ui->sbYScrollScale->setValue(Settings::value(Settings::Client::YScrollScale).toDouble());
@ -96,6 +104,7 @@ void ClientConfigDialog::load()
void ClientConfigDialog::resetToDefault()
{
ui->cbDynamicConnectTime->setChecked(Settings::defaultValue(Settings::Client::DynamicConnectionRetry).toBool());
ui->cbLanguageSync->setChecked(Settings::defaultValue(Settings::Client::LanguageSync).toBool());
ui->cbYScrollInvert->setChecked(Settings::defaultValue(Settings::Client::InvertYScroll).toBool());
ui->sbYScrollScale->setValue(Settings::defaultValue(Settings::Client::YScrollScale).toDouble());
@ -105,6 +114,7 @@ void ClientConfigDialog::resetToDefault()
void ClientConfigDialog::save()
{
Settings::setValue(Settings::Client::DynamicConnectionRetry, ui->cbDynamicConnectTime->isChecked());
Settings::setValue(Settings::Client::LanguageSync, ui->cbLanguageSync->isChecked());
Settings::setValue(Settings::Client::InvertYScroll, ui->cbYScrollInvert->isChecked());
Settings::setValue(Settings::Client::YScrollScale, ui->sbYScrollScale->value());

View file

@ -2,6 +2,14 @@
<ui version="4.0">
<class>ClientConfigDialog</class>
<widget class="QDialog" name="ClientConfigDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>391</width>
<height>176</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
@ -12,6 +20,16 @@
<string>Client Configuration</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="cbDynamicConnectTime">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allow the client to slow the rate it attempts to reconnect to the server when connections attempts are failing. The delay between connection attempts will start at 1 second intervals and can be a maxium of 5 minutes between connection attempts.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Use dynamic reconnection time based on connection attempts</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbLanguageSync">
<property name="text">

View file

@ -185,6 +185,14 @@ p, li { white-space: pre-wrap; }
<source>Reset to default values</source>
<translation type="unfinished">Restablecer valores predeterminados</translation>
</message>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allow the client to slow the rate it attempts to reconnect to the server when connections attempts are failing. The delay between connection attempts will start at 1 second intervals and can be a maxium of 5 minutes between connection attempts.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Permite que el cliente reduzca la frecuencia con la que intenta reconectarse al servidor cuando los intentos de conexión fallan. El intervalo entre intentos de conexión comenzará en 1 segundo y podrá alcanzar un máximo de 5 minutos.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<source>Use dynamic reconnection time based on connection attempts</source>
<translation type="unfinished">Utilizar un tiempo de reconexión dinámico basado en los intentos de conexión</translation>
</message>
</context>
<context>
<name>FingerprintDialog</name>

View file

@ -185,6 +185,14 @@ p, li { white-space: pre-wrap; }
<source>Reset to default values</source>
<translation type="unfinished">Ripristina i valori predefiniti</translation>
</message>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allow the client to slow the rate it attempts to reconnect to the server when connections attempts are failing. The delay between connection attempts will start at 1 second intervals and can be a maxium of 5 minutes between connection attempts.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Consente al client di rallentare la frequenza dei tentativi di riconnessione al server quando i tentativi di connessione falliscono. Il ritardo tra i tentativi di connessione inizierà a intervalli di 1 secondo, fino a raggiungere un massimo di 5 minuti tra un tentativo e l&apos;altro.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<source>Use dynamic reconnection time based on connection attempts</source>
<translation type="unfinished">Utilizza un tempo di riconnessione dinamico basato sui tentativi di connessione</translation>
</message>
</context>
<context>
<name>FingerprintDialog</name>

View file

@ -185,6 +185,14 @@ p, li { white-space: pre-wrap; }
<source>Reset to default values</source>
<translation>デフォルト値にリセットする</translation>
</message>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allow the client to slow the rate it attempts to reconnect to the server when connections attempts are failing. The delay between connection attempts will start at 1 second intervals and can be a maxium of 5 minutes between connection attempts.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;接続試行が失敗している場合、クライアントがサーバーへの再接続を試みる頻度を徐々に落とせるようにします。接続試行の間隔は当初1秒から開始され、最大で5分まで延長されます。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<source>Use dynamic reconnection time based on connection attempts</source>
<translation type="unfinished">接続試行回数に基づき、再接続時間を動的に調整する</translation>
</message>
</context>
<context>
<name>FingerprintDialog</name>

View file

@ -185,6 +185,14 @@ p, li { white-space: pre-wrap; }
<source>Reset to default values</source>
<translation type="unfinished">기본값으로 재설정</translation>
</message>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allow the client to slow the rate it attempts to reconnect to the server when connections attempts are failing. The delay between connection attempts will start at 1 second intervals and can be a maxium of 5 minutes between connection attempts.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;연결 시도가 실패할 경우, 클라이언트가 서버 재연결 시도 주기를 늦추도록 허용합니다. 연결 시도 간 지연 시간은 1초 간격으로 시작되며, 최대 5분까지 늘어날 수 있습니다.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<source>Use dynamic reconnection time based on connection attempts</source>
<translation type="unfinished">연결 시도 횟수에 따라 동적 재연결 시간을 사용합니다</translation>
</message>
</context>
<context>
<name>FingerprintDialog</name>

View file

@ -185,6 +185,14 @@ p, li { white-space: pre-wrap; }
<source>Reset to default values</source>
<translation type="unfinished">Сбросить до значений по умолчанию</translation>
</message>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allow the client to slow the rate it attempts to reconnect to the server when connections attempts are failing. The delay between connection attempts will start at 1 second intervals and can be a maxium of 5 minutes between connection attempts.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Позволить клиенту замедлять частоту попыток повторного подключения к серверу в случае неудачных попыток соединения. Интервал между попытками подключения будет начинаться с 1 секунды и может достигать максимума в 5 минут.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<source>Use dynamic reconnection time based on connection attempts</source>
<translation type="unfinished">Использовать динамическое время переподключения в зависимости от попыток подключения</translation>
</message>
</context>
<context>
<name>FingerprintDialog</name>

View file

@ -185,6 +185,14 @@ p, li { white-space: pre-wrap; }
<source>Reset to default values</source>
<translation type="unfinished">重置为默认值</translation>
</message>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allow the client to slow the rate it attempts to reconnect to the server when connections attempts are failing. The delay between connection attempts will start at 1 second intervals and can be a maxium of 5 minutes between connection attempts.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;允许客户端在连接尝试失败时,降低其重连服务器的频率。连接尝试之间的间隔将从 1 秒开始,最长可达 5 分钟。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<source>Use dynamic reconnection time based on connection attempts</source>
<translation type="unfinished">根据连接尝试次数,采用动态重连时间</translation>
</message>
</context>
<context>
<name>FingerprintDialog</name>