From bd38f3bc58be82d310fda5ee7489cc275b08354f Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 8 Feb 2026 14:34:09 -0800 Subject: [PATCH] fix(alfred): remove timer.unref() from SystemClock.sleep() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SystemClock.sleep() unconditionally called timer.unref() on every setTimeout. When a retry backoff or timeout race timer was the sole remaining event-loop handle, Node.js exited before the timer fired — silently aborting retries and timeouts. Remove the unref() call so policy timers keep the process alive while actively awaited. Callers that need graceful shutdown should use AbortSignal instead. Bump both packages to 0.10.2. --- CHANGELOG.md | 12 ++++++++++++ alfred-live/CHANGELOG.md | 6 ++++++ alfred-live/jsr.json | 2 +- alfred-live/package.json | 4 ++-- alfred/CHANGELOG.md | 6 ++++++ alfred/jsr.json | 2 +- alfred/package.json | 2 +- alfred/src/index.d.ts | 1 - alfred/src/utils/clock.js | 10 +--------- pnpm-lock.yaml | 2 +- 10 files changed, 31 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee6f3cf..b9867d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.10.2] - 2026-02-08 (@git-stunts/alfred) + +### Fixed + +- **Premature process exit**: `SystemClock.sleep()` no longer calls `timer.unref()`. The unref'd timer could become the sole event-loop handle during retry backoff or timeout races, causing Node.js to exit before the operation completed. Callers that need graceful shutdown should use `AbortSignal` instead. + ## [0.10.1] - 2026-02-06 (@git-stunts/alfred) ### Changed @@ -174,6 +180,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.10.2] - 2026-02-08 (@git-stunts/alfred-live) + +### Changed + +- Version bump to keep lockstep alignment with the Alfred package family (no API changes). + ## [0.10.1] - 2026-02-06 (@git-stunts/alfred-live) ### Added diff --git a/alfred-live/CHANGELOG.md b/alfred-live/CHANGELOG.md index 9724bf3..4be3d4e 100644 --- a/alfred-live/CHANGELOG.md +++ b/alfred-live/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.10.2] - 2026-02-08 + +### Changed + +- Version bump to keep lockstep alignment with the Alfred package family (no API changes). + ## [0.10.1] - 2026-02-06 ### Added diff --git a/alfred-live/jsr.json b/alfred-live/jsr.json index f2a7056..0bfb9d6 100644 --- a/alfred-live/jsr.json +++ b/alfred-live/jsr.json @@ -1,6 +1,6 @@ { "name": "@git-stunts/alfred-live", - "version": "0.10.1", + "version": "0.10.2", "description": "In-memory control plane for Alfred: adaptive values, config registry, command router.", "license": "Apache-2.0", "exports": { diff --git a/alfred-live/package.json b/alfred-live/package.json index 6854949..fd4e94c 100644 --- a/alfred-live/package.json +++ b/alfred-live/package.json @@ -1,6 +1,6 @@ { "name": "@git-stunts/alfred-live", - "version": "0.10.1", + "version": "0.10.2", "description": "In-memory control plane for Alfred: adaptive values, config registry, command router.", "type": "module", "sideEffects": false, @@ -16,7 +16,7 @@ "alfredctl": "./bin/alfredctl.js" }, "dependencies": { - "@git-stunts/alfred": "0.10.1" + "@git-stunts/alfred": "0.10.2" }, "engines": { "node": ">=20.0.0" diff --git a/alfred/CHANGELOG.md b/alfred/CHANGELOG.md index 5380046..ac15423 100644 --- a/alfred/CHANGELOG.md +++ b/alfred/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.10.2] - 2026-02-08 + +### Fixed + +- **Premature process exit**: `SystemClock.sleep()` no longer calls `timer.unref()`. The unref'd timer could become the sole event-loop handle during retry backoff or timeout races, causing Node.js to exit before the operation completed. Callers that need graceful shutdown should use `AbortSignal` instead. + ## [0.10.1] - 2026-02-06 ### Changed diff --git a/alfred/jsr.json b/alfred/jsr.json index f944604..9371b4f 100644 --- a/alfred/jsr.json +++ b/alfred/jsr.json @@ -1,6 +1,6 @@ { "name": "@git-stunts/alfred", - "version": "0.10.1", + "version": "0.10.2", "description": "Production-grade resilience patterns for async ops: retry/backoff+jitter, circuit breaker, bulkhead, timeout.", "license": "Apache-2.0", "exports": { diff --git a/alfred/package.json b/alfred/package.json index 8bb2b4d..6f655a3 100644 --- a/alfred/package.json +++ b/alfred/package.json @@ -1,6 +1,6 @@ { "name": "@git-stunts/alfred", - "version": "0.10.1", + "version": "0.10.2", "description": "Production-grade resilience patterns for async ops: retry/backoff+jitter, circuit breaker, bulkhead, timeout.", "type": "module", "sideEffects": false, diff --git a/alfred/src/index.d.ts b/alfred/src/index.d.ts index de0aeca..2d3501a 100644 --- a/alfred/src/index.d.ts +++ b/alfred/src/index.d.ts @@ -416,7 +416,6 @@ export class Policy { /** * System clock using real time. - * Uses runtime-aware timer management for clean process exits. */ export class SystemClock { /** Returns current time in milliseconds since Unix epoch. */ diff --git a/alfred/src/utils/clock.js b/alfred/src/utils/clock.js index fa8b8df..5dc80d9 100644 --- a/alfred/src/utils/clock.js +++ b/alfred/src/utils/clock.js @@ -9,7 +9,6 @@ /** * System clock using real time. - * Uses runtime-aware timer management (unref) to allow clean process exits. */ export class SystemClock { /** @@ -22,19 +21,12 @@ export class SystemClock { /** * Sleeps for the specified duration. - * Timer is unref'd to prevent blocking process exit. * @param {number} ms - Milliseconds to sleep * @returns {Promise} */ async sleep(ms) { return new Promise((resolve) => { - const timer = setTimeout(resolve, ms); - if (typeof timer === 'object' && typeof timer.unref === 'function') { - timer.unref(); - } else if (typeof Deno !== 'undefined' && typeof Deno.unrefTimer === 'function') { - // Deno returns a number ID - Deno.unrefTimer(timer); - } + setTimeout(resolve, ms); }); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 548098c..f49031b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,7 +29,7 @@ importers: alfred-live: dependencies: '@git-stunts/alfred': - specifier: 0.10.1 + specifier: 0.10.2 version: link:../alfred devDependencies: '@eslint/js':