From deb5b3d025ee42a78816b5a57489722239bbbbeb Mon Sep 17 00:00:00 2001 From: James Andariese Date: Sun, 27 Feb 2022 02:17:48 -0600 Subject: Add configurable hibernation interval after auto-wakeup (#2422) --- .../settings/settings/EditSettingsForm.js | 2 + src/config.ts | 13 +++++ src/containers/settings/EditSettingsScreen.js | 27 +++++++++++ src/i18n/locales/en-US.json | 2 + src/stores/ServicesStore.js | 56 ++++++++++++++++++++-- 5 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index bdb8484d4..c92bde346 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js @@ -424,6 +424,8 @@ class EditSettingsForm extends Component {

+
diff --git a/src/config.ts b/src/config.ts index 5c9fbaee4..3dbcd809b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -58,6 +58,17 @@ export const WAKE_UP_STRATEGIES = { 3600: 'Wake up after 1hour', }; +export const WAKE_UP_HIBERNATION_STRATEGIES = { + 0: 'Use main hibernation strategy', + 10: 'Extremely Fast Hibernation (10sec)', + 30: 'Very Fast Hibernation (30sec)', + 60: 'Fast Hibernation (1min)', + 300: 'Normal Hibernation (5min)', + 600: 'Slow Hibernation (10min)', + 1800: 'Very Slow Hibernation (30min)', + 3600: 'Extremely Slow Hibernation (1hour)', +}; + export const NAVIGATION_BAR_BEHAVIOURS = { custom: 'Show navigation bar on custom websites only', always: 'Show navigation bar on all services', @@ -217,6 +228,8 @@ export const DEFAULT_APP_SETTINGS = { hibernateOnStartup: true, hibernationStrategy: '300', // seconds wakeUpStrategy: '300', // seconds + wakeUpHibernationStrategy: '0', // seconds -- 0 means do the same as hibernationStrategy + wakeUpHibernationSplay: true, inactivityLock: 0, automaticUpdates: true, universalDarkMode: true, diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js index eff5f20ff..6e405cd92 100644 --- a/src/containers/settings/EditSettingsScreen.js +++ b/src/containers/settings/EditSettingsScreen.js @@ -20,6 +20,7 @@ import { DEFAULT_SETTING_KEEP_ALL_WORKSPACES_LOADED, DEFAULT_IS_FEATURE_ENABLED_BY_USER, WAKE_UP_STRATEGIES, + WAKE_UP_HIBERNATION_STRATEGIES, SPLIT_COLUMNS_MIN, SPLIT_COLUMNS_MAX, } from '../../config'; @@ -115,6 +116,14 @@ const messages = defineMessages({ id: 'settings.app.form.wakeUpStrategy', defaultMessage: 'Wake up strategy', }, + wakeUpHibernationStrategy: { + id: 'settings.app.form.wakeUpHibernationStrategy', + defaultMessage: 'Hibernation strategy after automatic wake up', + }, + wakeUpHibernationSplay: { + id: 'settings.app.form.wakeUpHibernationSplay', + defaultMessage: 'Splay hibernate/wake cycles to reduce load', + }, predefinedTodoServer: { id: 'settings.app.form.predefinedTodoServer', defaultMessage: 'Todo Server', @@ -295,6 +304,8 @@ class EditSettingsScreen extends Component { hibernateOnStartup: Boolean(settingsData.hibernateOnStartup), hibernationStrategy: Number(settingsData.hibernationStrategy), wakeUpStrategy: Number(settingsData.wakeUpStrategy), + wakeUpHibernationStrategy: Number(settingsData.wakeUpHibernationStrategy), + wakeUpHibernationSplay: Boolean(settingsData.wakeUpHibernationSplay), predefinedTodoServer: settingsData.predefinedTodoServer, customTodoServer: settingsData.customTodoServer, lockingFeatureEnabled: Boolean(settingsData.lockingFeatureEnabled), @@ -391,6 +402,11 @@ class EditSettingsScreen extends Component { sort: false, }); + const wakeUpHibernationStrategies = getSelectOptions({ + locales: WAKE_UP_HIBERNATION_STRATEGIES, + sort: false, + }); + const todoApp = getSelectOptions({ locales: TODO_APPS, sort: false, @@ -511,6 +527,17 @@ class EditSettingsScreen extends Component { options: wakeUpStrategies, default: DEFAULT_APP_SETTINGS.wakeUpStrategy, }, + wakeUpHibernationStrategy: { + label: intl.formatMessage(messages.wakeUpHibernationStrategy), + value: settings.all.app.wakeUpHibernationStrategy, + options: wakeUpHibernationStrategies, + default: DEFAULT_APP_SETTINGS.wakeUpHibernationStrategy, + }, + wakeUpHibernationSplay: { + label: intl.formatMessage(messages.wakeUpHibernationSplay), + value: settings.all.app.wakeUpHibernationSplay, + default: DEFAULT_APP_SETTINGS.wakeUpHibernationSplay, + }, predefinedTodoServer: { label: intl.formatMessage(messages.predefinedTodoServer), value: settings.all.app.predefinedTodoServer, diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 3f1e5728f..f6b53d501 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -243,6 +243,8 @@ "settings.app.form.universalDarkMode": "Enable universal Dark Mode", "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", "settings.app.form.useVerticalStyle": "Use horizontal style", + "settings.app.form.wakeUpHibernationSplay": "Splay hibernate/wake cycles to reduce load", + "settings.app.form.wakeUpHibernationStrategy": "Hibernation strategy after automatic wake up", "settings.app.form.wakeUpStrategy": "Wake up strategy", "settings.app.headlineAdvanced": "Advanced", "settings.app.headlineAppearance": "Appearance", diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index e546850f9..e2bfd22f3 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -239,7 +239,7 @@ export default class ServicesStore extends Store { ms(`${this.stores.settings.all.app.wakeUpStrategy}s`) ) { // If service is in hibernation and the wakeup time has elapsed, wake it. - this._awake({ serviceId: service.id }); + this._awake({ serviceId: service.id, automatic: true }); } } @@ -1043,11 +1043,59 @@ export default class ServicesStore extends Store { service.lastHibernated = Date.now(); } - @action _awake({ serviceId }) { + @action _awake({ serviceId, automatic }) { + const now = Date.now(); const service = this.one(serviceId); - debug(`Waking up from service hibernation for ${service.name}`); + const automaticTag = automatic ? ' automatically ' : ' '; + debug( + `Waking up${automaticTag}from service hibernation for ${service.name}`, + ); + + if (automatic) { + // if this is an automatic wake up, use the wakeUpHibernationStrategy + // which sets the lastUsed time to an offset from now rather than to now. + // Also add an optional random splay to desync the wakeups and + // potentially reduce load. + // + // offsetNow = now - (hibernationStrategy - wakeUpHibernationStrategy) + // + // if wUHS = hS = 60, offsetNow = now. hibernation again in 60 seconds. + // + // if wUHS = 20 and hS = 60, offsetNow = now - 40. hibernation again in + // 20 seconds. + // + // possibly also include splay in wUHS before subtracting from hS. + // + const mainStrategy = this.stores.settings.all.app.hibernationStrategy; + let strategy = this.stores.settings.all.app.wakeUpHibernationStrategy; + debug(`wakeUpHibernationStrategy = ${strategy}`); + debug(`hibernationStrategy = ${mainStrategy}`); + if (!strategy || strategy < 1) { + strategy = this.stores.settings.all.app.hibernationStrategy; + } + let splay = 0; + // Add splay. This will keep the service awake a little longer. + if ( + this.stores.settings.all.app.wakeUpHibernationSplay && + Math.random() >= 0.5 + ) { + // Add 10 additional seconds 50% of the time. + splay = 10; + debug('Added splay'); + } else { + debug('skipping splay'); + } + // wake up again in strategy + splay seconds instead of mainStrategy seconds. + service.lastUsed = now - ms(`${mainStrategy - (strategy + splay)}s`); + } else { + service.lastUsed = now; + } + debug( + `Setting service.lastUsed to ${service.lastUsed} (${ + (now - service.lastUsed) / 1000 + }s ago)`, + ); service.isHibernationRequested = false; - service.lastUsed = Date.now(); service.lastHibernated = null; } -- cgit v1.2.3-54-g00ecf