Skip to main content
Documentation
Preview
You're viewing the Next docs — a rolling preview of in-development changes. The current release docs may differ.

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:

dev.nexigon.ota.config
{
  "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:MM on 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.
  • days lists the days on which a range starts, so the Friday range ends on Saturday at 04
    . Without days, a range starts every day.
  • An empty ranges list 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:

dev.nexigon.ota.status
{
  "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:

dev.nexigon.ota.config
{
  "path": "acme/gateway-os/stable",
  "retry": {
    "maxAttempts": 5,
    "initialDelaySecs": 900,
    "maxDelaySecs": 3600,
    "cooldownSecs": 86400
  }
}
  • maxAttempts limits 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 initialDelaySecs and doubles after each failed attempt, up to maxDelaySecs.
  • cooldownSecs is 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.