mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-02-20 17:52:51 +00:00
Add a random jitter to target state polls, and a config var to ignore update notifications and not poll immediately after startup
This commit does two related things: * We make the poll interval a random time between 0.5 and 1.5 times the configured interval. * We introduce the BALENA_SUPERVISOR_INSTANT_UPDATE_TRIGGER configuration variable, that defaults to true. If this variable is set to false, then calls to /v1/update are ignored, and on startup the supervisor waits for a poll interval before getting the target state. This will help especially on cases where there's a large number of devices on a single network. By disabling instant updates and setting a large poll interval, we can now achieve a sitation where not all devices apply an update at the same time, which can help avoid overwhelming the network. Change-type: minor Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
This commit is contained in:
parent
77d5c10aee
commit
8f07bf62de
@ -363,7 +363,7 @@ export class APIBinder {
|
||||
'Trying to start poll without initializing API client',
|
||||
);
|
||||
}
|
||||
this.pollTargetState();
|
||||
this.pollTargetState(true);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
@ -568,19 +568,27 @@ export class APIBinder {
|
||||
});
|
||||
}
|
||||
|
||||
private async pollTargetState(): Promise<void> {
|
||||
private async pollTargetState(isInitialCall: boolean = false): Promise<void> {
|
||||
// TODO: Remove the checkInt here with the config changes
|
||||
let pollInterval = await this.config.get('appUpdatePollInterval');
|
||||
const { appUpdatePollInterval, instantUpdates } = await this.config.getMany(
|
||||
['appUpdatePollInterval', 'instantUpdates'],
|
||||
);
|
||||
|
||||
try {
|
||||
await this.getAndSetTargetState(false);
|
||||
this.targetStateFetchErrors = 0;
|
||||
} catch (e) {
|
||||
pollInterval = Math.min(
|
||||
pollInterval,
|
||||
15000 * 2 ** this.targetStateFetchErrors,
|
||||
);
|
||||
++this.targetStateFetchErrors;
|
||||
// We add jitter to the poll interval so that it's between 0.5 and 1.5 times
|
||||
// the configured interval
|
||||
let pollInterval = (0.5 + Math.random()) * appUpdatePollInterval;
|
||||
|
||||
if (instantUpdates || !isInitialCall) {
|
||||
try {
|
||||
await this.getAndSetTargetState(false);
|
||||
this.targetStateFetchErrors = 0;
|
||||
} catch (e) {
|
||||
pollInterval = Math.min(
|
||||
appUpdatePollInterval,
|
||||
15000 * 2 ** this.targetStateFetchErrors,
|
||||
);
|
||||
++this.targetStateFetchErrors;
|
||||
}
|
||||
}
|
||||
|
||||
await Bluebird.delay(pollInterval);
|
||||
@ -912,7 +920,15 @@ export class APIBinder {
|
||||
router.post('/v1/update', (req, res) => {
|
||||
apiBinder.eventTracker.track('Update notification');
|
||||
if (apiBinder.readyForUpdates) {
|
||||
apiBinder.getAndSetTargetState(req.body.force, true).catch(_.noop);
|
||||
this.config.get('instantUpdates').then(instantUpdates => {
|
||||
if (instantUpdates) {
|
||||
apiBinder.getAndSetTargetState(req.body.force, true).catch(_.noop);
|
||||
} else {
|
||||
console.log(
|
||||
'Ignoring update notification because instant updates are disabled',
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
res.sendStatus(204);
|
||||
});
|
||||
|
@ -66,6 +66,10 @@ export const schemaTypes = {
|
||||
type: PermissiveNumber,
|
||||
default: 60000,
|
||||
},
|
||||
instantUpdates: {
|
||||
type: PermissiveBoolean,
|
||||
default: true,
|
||||
},
|
||||
mixpanelToken: {
|
||||
type: t.string,
|
||||
default: constants.defaultMixpanelToken,
|
||||
|
@ -185,6 +185,11 @@ export const schema = {
|
||||
mutable: true,
|
||||
removeIfNull: false,
|
||||
},
|
||||
instantUpdates: {
|
||||
source: 'db',
|
||||
mutable: true,
|
||||
removeIfNull: false,
|
||||
},
|
||||
};
|
||||
|
||||
export type Schema = typeof schema;
|
||||
|
@ -68,6 +68,11 @@ export class DeviceConfig {
|
||||
varType: 'int',
|
||||
defaultValue: '60000',
|
||||
},
|
||||
instantUpdates: {
|
||||
envVarName: 'SUPERVISOR_INSTANT_UPDATE_TRIGGER',
|
||||
varType: 'bool',
|
||||
defaultValue: 'true',
|
||||
},
|
||||
localMode: {
|
||||
envVarName: 'SUPERVISOR_LOCAL_MODE',
|
||||
varType: 'bool',
|
||||
|
@ -21,6 +21,7 @@ mockedInitialConfig = {
|
||||
'RESIN_SUPERVISOR_DELTA_RETRY_COUNT': '30'
|
||||
'RESIN_SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
|
||||
'RESIN_SUPERVISOR_DELTA_VERSION': '2'
|
||||
'RESIN_SUPERVISOR_INSTANT_UPDATE_TRIGGER': 'true'
|
||||
'RESIN_SUPERVISOR_LOCAL_MODE': 'false'
|
||||
'RESIN_SUPERVISOR_LOG_CONTROL': 'true'
|
||||
'RESIN_SUPERVISOR_OVERRIDE_LOCK': 'false'
|
||||
@ -40,6 +41,7 @@ testTarget1 = {
|
||||
'SUPERVISOR_DELTA_RETRY_COUNT': '30'
|
||||
'SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
|
||||
'SUPERVISOR_DELTA_VERSION': '2'
|
||||
'SUPERVISOR_INSTANT_UPDATE_TRIGGER': 'true'
|
||||
'SUPERVISOR_LOCAL_MODE': 'false'
|
||||
'SUPERVISOR_LOG_CONTROL': 'true'
|
||||
'SUPERVISOR_OVERRIDE_LOCK': 'false'
|
||||
@ -122,6 +124,7 @@ testTargetWithDefaults2 = {
|
||||
'SUPERVISOR_DELTA_RETRY_COUNT': '30'
|
||||
'SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
|
||||
'SUPERVISOR_DELTA_VERSION': '2'
|
||||
'SUPERVISOR_INSTANT_UPDATE_TRIGGER': 'true'
|
||||
'SUPERVISOR_LOCAL_MODE': 'false'
|
||||
'SUPERVISOR_LOG_CONTROL': 'true'
|
||||
'SUPERVISOR_OVERRIDE_LOCK': 'false'
|
||||
|
Loading…
x
Reference in New Issue
Block a user