Maintenance Windows and Retries
The desired state can include two policies. A maintenance window restricts when
an update may interrupt a device. A retry policy controls how often and how soon
a device attempts a failed update again. Both are optional features of an
integration. An integration that supports them lists window and retry in
the capabilities of its status.
Maintenance Windows
A maintenance window restricts activation, the step of an update that interrupts the device’s operation, such as the reboot into the new version. Integrations may download and install an update outside the window if doing so does not interrupt operation. For example, on a system with A/B partitions, an integration can write the new version to the inactive partition during the day and reboot into it at night.
A window consists of time ranges in the device’s local time. Each range has a start, an end, and optionally the days on which it starts:
{
"path": "acme/gateway-os/stable",
"window": {
"ranges": [
{
"days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"start": "22:00",
"end": "04:00"
},
{ "days": ["saturday", "sunday"], "start": "00:00", "end": "00:00" }
]
}
}This window allows activation from 22
to 04 after each weekday and during the entire weekend. Ranges follow these rules:- Times use the format
HH:MMon a 24-hour clock. The start is inclusive, and the end is exclusive. - An end at or before the start lies on the following day. In the example, the weekday range runs from 22 until 04 the next morning, and the weekend range spans 24 hours.
dayslists the days on which a range starts, so the Friday range ends on Saturday at 04. Withoutdays, a range starts every day.- An empty
rangeslist never allows activation. To keep a device at its current version on purpose, hold it instead.
The window applies to the start of activation. An activation that starts inside the window completes even if it runs past the end. Committing a new version after it booted is not restricted.
Local Time
Devices evaluate the window in the time zone of their operating system, such as
the zone configured in /etc/localtime. Nexigon does not set this time zone.
With correctly configured devices, a fleet spread across time zones updates at
night everywhere.
A device whose clock is not synchronized, for example after booting without
network access, treats the window as closed. How an integration detects this
depends on the system. On systems with systemd, for example, timedatectl show --property=NTPSynchronized reports it. A device without any time
synchronization therefore never activates an update while a window is
configured.
Waiting for the Window
While a device waits for its window, it reports the state blocked with the
code window, and nextAttemptAt holds the time at which the window opens.
For example, a device in Berlin reports on a Friday afternoon:
{
"currentVersion": "2.1",
"state": "blocked",
"blocked": { "code": "window" },
"nextAttemptAt": "2026-10-16T20:00:00Z"
}While its clock is not synchronized, the device reports the same state without
nextAttemptAt.
If an update requires installing a checkpoint first, each step has its own activation. After a step completes, the next check plans the following step, which the device activates if the window is still open.
Retries
An attempt starts when the device begins downloading a version and ends when the version is committed or the attempt fails. Download and installation errors, failed boots, and rollbacks are failed attempts. Errors before an attempt starts, such as an unreachable Nexigon Hub while resolving the configured path, do not count. The integration tries again on its next check.
A retry policy limits the failed attempts for each version and spaces them out:
{
"path": "acme/gateway-os/stable",
"retry": {
"maxAttempts": 5,
"initialDelaySecs": 900,
"maxDelaySecs": 3600,
"cooldownSecs": 86400
}
}maxAttemptslimits the failed attempts for one version. Without it, the integration keeps trying.- After a failed attempt, the integration waits before the next attempt. The
delay starts at
initialDelaySecsand doubles after each failed attempt, up tomaxDelaySecs. cooldownSecsis the time after the last allowed attempt fails before the device starts over with a new round of attempts. Without it, the device stops attempting the version.
With this policy, the device attempts a version up to five times. After the first four failures, it waits 15, 30, 60, and 60 minutes, as the delay reaches its maximum. After the fifth failure, it waits one day and then starts over.
The status reports the number of consecutive failed attempts as failureCount,
the latest error as lastError, and the time of the next attempt as
nextAttemptAt. The count belongs to the version in nextVersionId. It resets
to zero when that version changes, when an update succeeds, when the cooldown
ends, or when the configuration is written.
Retrying after the Limit
Once failureCount reaches maxAttempts, the device remains in the state
failed. With a cooldown, nextAttemptAt holds the end of the cooldown.
Without one, nextAttemptAt is absent, and the device stops attempting the
version.
To retry right away, write dev.nexigon.ota.config again, even with an
unchanged value, and run the nexigon.ota.check command. Every write
increments the property’s version.
The integration reports the version it last read as configVersion in its
status and resets failureCount when the version changes. Retry Update in
the web interface performs both steps.
A write to the desired state expresses a new decision, so the device attempts
the update again. This also applies to other changes, such as a new maintenance
window. Because the retry is part of the desired state, a device that is
offline at the time still sees it when it reconnects. Its configVersion shows
whether it has done so.
Defaults
A setting can come from three places. The dev.nexigon.ota.config property
overrides the defaults built into the image, and the integration applies its
own defaults for settings that neither specifies. To remove a default built
into the image, set the field to null in the property, as described in the
reference.
Integrations should report the resulting effective configuration in the
config field of the status. Clients can then show how a device behaves
without knowing the defaults of its image or integration.