diff --git a/README.md b/README.md index fa27a2f..305cb7d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@
-
+
diff --git a/backend/package.json b/backend/package.json
index d0ee2a3..8da6905 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "mikrotik-manager-backend",
- "version": "0.24.4-beta",
+ "version": "0.24.5-beta",
"description": "Mikrotik Network Management Platform - Backend API",
"main": "dist/index.js",
"scripts": {
diff --git a/backend/src/services/FirmwareOrchestrator.ts b/backend/src/services/FirmwareOrchestrator.ts
index 9050948..5fedd23 100644
--- a/backend/src/services/FirmwareOrchestrator.ts
+++ b/backend/src/services/FirmwareOrchestrator.ts
@@ -98,12 +98,16 @@ export class FirmwareOrchestrator {
// Waves stay strictly sequential -- that is the decision point, and it is
// what makes wave 1 a canary. Concurrency applies only *within* a wave.
//
- // At the default of 1 this is the previous behaviour with one difference
- // worth stating: halting is evaluated at the end of a wave rather than the
- // instant a device fails. With a wave of one those are the same moment. With
- // a larger wave it is the trade the operator asked for (#135) -- more devices
- // carry a bad build before anything stops, in exchange for not waiting out
- // ten five-minute reboots in series.
+ // Halt-on-failure stops *starting* further devices the moment a failure is
+ // known, rather than at the end of the wave. Devices already in flight are
+ // allowed to finish, because interrupting a device mid-write is how you
+ // brick it.
+ //
+ // At the default concurrency of 1 that is exactly the previous behaviour:
+ // a failure stops the next device immediately. Only devices genuinely
+ // running side by side can carry a bad build, which is the unavoidable part
+ // of the trade in #135 -- not a wider blast radius imposed on rollouts that
+ // never asked for concurrency.
for (const wave of waves) {
if (this.cancelRequested || halted) break;
const inWave = items.filter((i) => i.wave === wave);
@@ -113,11 +117,15 @@ export class FirmwareOrchestrator {
`${inWave.length} device(s), up to ${concurrency} at once`);
}
- const results = await mapWithConcurrency(inWave, concurrency, (item) =>
- this.cancelRequested
- ? Promise.resolve(false)
- : this.upgradeDevice(rollout, item)
- );
+ let failedInWave = false;
+ const results = await mapWithConcurrency(inWave, concurrency, async (item) => {
+ if (this.cancelRequested) return false;
+ // Do not begin another device once this wave has already failed.
+ if (rollout.halt_on_failure && failedInWave) return false;
+ const ok = await this.upgradeDevice(rollout, item);
+ if (!ok) failedInWave = true;
+ return ok;
+ });
if (rollout.halt_on_failure && results.some((ok) => !ok)) {
halted = true;
diff --git a/docs/firmware.md b/docs/firmware.md
index 0f54fd8..24e53f2 100644
--- a/docs/firmware.md
+++ b/docs/firmware.md
@@ -55,10 +55,11 @@ everything after it.
There are two costs, and both are worth understanding before you raise it.
-**Halting becomes less precise.** With one device at a time, a failure stops the
-rollout immediately. Running several at once, the wave finishes first — so a wave of
-five can put a bad build on five devices before anything stops. At the default of 1
-these are the same moment.
+**Halting becomes less precise.** A failure stops any further device from *starting*,
+immediately — but devices already running finish, because interrupting one mid-write is
+how you brick it. So with **At once** set to five, up to five devices can carry a bad
+build before anything stops. At the default of 1 nothing else has started, so a failure
+stops the rollout exactly as it always has.
**Devices reboot together.** That is fine for independent routers. It is not fine for
a switch that the others are reached *through*: rebooting it alongside them cuts the
diff --git a/frontend/package.json b/frontend/package.json
index 9edff39..6022fce 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,6 +1,6 @@
{
"name": "mikrotik-manager-frontend",
- "version": "0.24.4-beta",
+ "version": "0.24.5-beta",
"private": true,
"type": "module",
"scripts": {
diff --git a/frontend/src/version.ts b/frontend/src/version.ts
index 7b1d20b..d471792 100644
--- a/frontend/src/version.ts
+++ b/frontend/src/version.ts
@@ -1 +1 @@
-export const APP_VERSION = 'v0.24.4 Beta';
+export const APP_VERSION = 'v0.24.5 Beta';