Linear back-off

pull/207/head
M66B 3 years ago
parent f5a2cc2d82
commit 88d4b5cf66

@ -3447,8 +3447,11 @@ for example if the internet connection is bad or a firewall or a VPN is blocking
FairEmail will retry one time after waiting 8 seconds while keeping the device awake (=use battery power). FairEmail will retry one time after waiting 8 seconds while keeping the device awake (=use battery power).
If this fails, FairEmail will schedule an alarm to retry after 5, 15, 30 and eventually every 60 minutes and let the device sleep (=no battery usage). If this fails, FairEmail will schedule an alarm to retry after 5, 15, 30 and eventually every 60 minutes and let the device sleep (=no battery usage).
By temporarily enabling debug mode in the miscellaneous settings, you can disable this logarithmic back-off scheme (since version 1.1855).
This will result in using a linear back-off scheme, which means that after each failure the wait time will be increased by 1 minute up to 60 minutes.
Note that [Android doze mode](https://developer.android.com/training/monitoring-device-state/doze-standby) Note that [Android doze mode](https://developer.android.com/training/monitoring-device-state/doze-standby)
does not allow to wake the device earlier than after 15 minutes. does not allow to wake the device earlier than after 15 minutes when doze mode is enabled.
*Force sync* in the three-dots menu of the unified inbox can be used to let FairEmail attempt to reconnect without waiting. *Force sync* in the three-dots menu of the unified inbox can be used to let FairEmail attempt to reconnect without waiting.

@ -2315,76 +2315,83 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
if (state.isRunning()) { if (state.isRunning()) {
long now = new Date().getTime(); long now = new Date().getTime();
boolean logarithmic_backoff = prefs.getBoolean("logarithmic_backoff", true);
// Check for fast successive server, connectivity, etc failures if (logarithmic_backoff) {
long poll_interval = Math.min(account.poll_interval, CONNECT_BACKOFF_ALARM_START); // Check for fast successive server, connectivity, etc failures
long fail_threshold = poll_interval * 60 * 1000L * FAST_FAIL_THRESHOLD / 100; long poll_interval = Math.min(account.poll_interval, CONNECT_BACKOFF_ALARM_START);
long was_connected = (account.last_connected == null ? 0 : now - account.last_connected); long fail_threshold = poll_interval * 60 * 1000L * FAST_FAIL_THRESHOLD / 100;
if (was_connected < fail_threshold) { long was_connected = (account.last_connected == null ? 0 : now - account.last_connected);
if (state.getBackoff() == CONNECT_BACKOFF_START) { if (was_connected < fail_threshold) {
fast_fails++; if (state.getBackoff() == CONNECT_BACKOFF_START) {
if (fast_fails == 1) fast_fails++;
first_fail = now; if (fast_fails == 1)
else if (fast_fails >= FAST_FAIL_COUNT) { first_fail = now;
long avg_fail = (now - first_fail) / fast_fails; else if (fast_fails >= FAST_FAIL_COUNT) {
if (avg_fail < fail_threshold) { long avg_fail = (now - first_fail) / fast_fails;
long missing = (fail_threshold - avg_fail) * fast_fails; if (avg_fail < fail_threshold) {
int compensate = (int) (missing / (CONNECT_BACKOFF_ALARM_START * 60 * 1000L)); long missing = (fail_threshold - avg_fail) * fast_fails;
if (compensate > 0) { int compensate = (int) (missing / (CONNECT_BACKOFF_ALARM_START * 60 * 1000L));
if (was_connected != 0 && was_connected < CONNECT_BACKOFF_GRACE) if (compensate > 0) {
compensate = 1; if (was_connected != 0 && was_connected < CONNECT_BACKOFF_GRACE)
compensate = 1;
int backoff = compensate * CONNECT_BACKOFF_ALARM_START;
if (backoff > CONNECT_BACKOFF_ALARM_MAX) int backoff = compensate * CONNECT_BACKOFF_ALARM_START;
backoff = CONNECT_BACKOFF_ALARM_MAX; if (backoff > CONNECT_BACKOFF_ALARM_MAX)
backoff = CONNECT_BACKOFF_ALARM_MAX;
String msg = "Fast" +
" fails=" + fast_fails + String msg = "Fast" +
" was=" + (was_connected / 1000L) + " fails=" + fast_fails +
" first=" + ((now - first_fail) / 1000L) + " was=" + (was_connected / 1000L) +
" poll=" + poll_interval + " first=" + ((now - first_fail) / 1000L) +
" avg=" + (avg_fail / 1000L) + "/" + (fail_threshold / 1000L) + " poll=" + poll_interval +
" missing=" + (missing / 1000L) + " avg=" + (avg_fail / 1000L) + "/" + (fail_threshold / 1000L) +
" compensate=" + compensate + " missing=" + (missing / 1000L) +
" backoff=" + backoff + " compensate=" + compensate +
" host=" + account.host + " backoff=" + backoff +
" ex=" + Log.formatThrowable(last_fail, false); " host=" + account.host +
if (compensate > 2) " ex=" + Log.formatThrowable(last_fail, false);
Log.e(msg); if (compensate > 2)
EntityLog.log(this, EntityLog.Type.Account, account, msg); Log.e(msg);
EntityLog.log(this, EntityLog.Type.Account, account, msg);
state.setBackoff(backoff * 60);
state.setBackoff(backoff * 60);
}
} }
} }
} }
} else {
fast_fails = 0;
first_fail = 0;
} }
} else {
fast_fails = 0;
first_fail = 0;
} }
int backoff = state.getBackoff(); int backoff = state.getBackoff();
int recently = (lastLost + LOST_RECENTLY < now ? 1 : 2); int recently = (lastLost + LOST_RECENTLY < now ? 1 : 2);
boolean logarithmic_backoff = prefs.getBoolean("logarithmic_backoff", true);
EntityLog.log(this, EntityLog.Type.Account, account, EntityLog.log(this, EntityLog.Type.Account, account,
account.name + " backoff=" + backoff + account.name + " backoff=" + backoff +
" recently=" + recently + "x" + " recently=" + recently + "x" +
" logarithmic=" + logarithmic_backoff); " logarithmic=" + logarithmic_backoff);
if (!logarithmic_backoff) if (logarithmic_backoff) {
backoff = CONNECT_BACKOFF_START; if (backoff < CONNECT_BACKOFF_MAX)
state.setBackoff(backoff * 2);
if (backoff < CONNECT_BACKOFF_MAX) else if (backoff == CONNECT_BACKOFF_MAX)
state.setBackoff(backoff * 2); if (AlarmManagerCompatEx.hasExactAlarms(this))
else if (backoff == CONNECT_BACKOFF_MAX) state.setBackoff(CONNECT_BACKOFF_INTERMEDIATE * 60);
if (AlarmManagerCompatEx.hasExactAlarms(this)) else
state.setBackoff(CONNECT_BACKOFF_INTERMEDIATE * 60); state.setBackoff(CONNECT_BACKOFF_ALARM_START * 60);
else else if (backoff == CONNECT_BACKOFF_INTERMEDIATE * 60)
state.setBackoff(CONNECT_BACKOFF_ALARM_START * 60); state.setBackoff(CONNECT_BACKOFF_ALARM_START * 60);
else if (backoff == CONNECT_BACKOFF_INTERMEDIATE * 60) else if (backoff < CONNECT_BACKOFF_ALARM_MAX * 60) {
state.setBackoff(CONNECT_BACKOFF_ALARM_START * 60); int b = backoff * 2;
else if (backoff < CONNECT_BACKOFF_ALARM_MAX * 60) { if (b > CONNECT_BACKOFF_ALARM_MAX * 60)
int b = backoff * 2; b = CONNECT_BACKOFF_ALARM_MAX * 60;
state.setBackoff(b);
}
} else {
// Linear back-off
int b = backoff + 60;
if (b > CONNECT_BACKOFF_ALARM_MAX * 60) if (b > CONNECT_BACKOFF_ALARM_MAX * 60)
b = CONNECT_BACKOFF_ALARM_MAX * 60; b = CONNECT_BACKOFF_ALARM_MAX * 60;
state.setBackoff(b); state.setBackoff(b);

Loading…
Cancel
Save