@deepseek-ai/dsh-timeout 0.2.1-alpha.1 → 0.2.1-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/lib/index.js +12 -3
- package/lib/types/index.d.ts +11 -2
- package/package.json +3 -3
package/README.i18n.yaml
CHANGED
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
en: ceea0b46e6b8e15f
|
|
46
46
|
zh: de87dccf08764061
|
|
47
47
|
/deepseek-ai-dsh-timeout/understand-the-implementation/why-an-idle-watchdog-rearms:
|
|
48
|
-
en:
|
|
49
|
-
zh:
|
|
48
|
+
en: f7cd0e8ba2937f0f
|
|
49
|
+
zh: d17d546c5587b04e
|
|
50
50
|
/deepseek-ai-dsh-timeout/further-exploration:
|
|
51
51
|
en: 4c29a947e28047ad
|
|
52
52
|
zh: d80f5ecb50b16203
|
package/README.md
CHANGED
|
@@ -103,7 +103,7 @@ The library is built on one boundary: share the timing and classification, keep
|
|
|
103
103
|
|
|
104
104
|
### Why an idle watchdog rearms
|
|
105
105
|
|
|
106
|
-
`idleWatchdog` keeps one stable fused signal and arms the timer only while `next()` is outstanding; resolution disarms, later demand or `pulse()` rearms, disposal clears, and concurrent demand rejects.
|
|
106
|
+
`idleWatchdog` keeps one stable fused signal and arms the timer only while `next()` is outstanding; resolution disarms, later demand or `pulse()` rearms, disposal clears, and concurrent demand rejects. Unlike `deadline()`, an idle watchdog settles its outstanding demand on its own deadline: a read the transport leaves pending after an abort rejects `next()` with the watchdog's `TimeoutReason`, so a transport that never observes the signal cannot extend the wait past the idle interval. The signal still tells the transport to release its own resources — the DeepSeek and pi-ai adapters close their response body or SDK request on abort.
|
|
107
107
|
|
|
108
108
|
</details>
|
|
109
109
|
|
package/README.zh.md
CHANGED
|
@@ -103,7 +103,7 @@ timer 只在某个迭代器 `next()` 尚未完成时启动,并会因不产生
|
|
|
103
103
|
|
|
104
104
|
### 空闲 watchdog 为何重新启动
|
|
105
105
|
|
|
106
|
-
`idleWatchdog` 保持一个稳定的融合信号,只在 `next()` 尚未完成时启动 timer;完成后停止,后续需求或 `pulse()` 重新启动,dispose
|
|
106
|
+
`idleWatchdog` 保持一个稳定的融合信号,只在 `next()` 尚未完成时启动 timer;完成后停止,后续需求或 `pulse()` 重新启动,dispose(资源释放)时清除,并发需求被拒绝。与 `deadline()` 不同,空闲 watchdog 会按自己的截止时间结算尚未完成的 demand:传输层在 abort 之后仍挂起的读取会让 `next()` 以该 watchdog 的 `TimeoutReason` reject,因此完全不观察信号的传输层也无法把等待拖过空闲间隔。信号仍用于让传输层释放自身资源——DeepSeek 与 pi-ai 适配器会在中止时关闭响应正文或 SDK 请求。
|
|
107
107
|
|
|
108
108
|
</details>
|
|
109
109
|
|
package/lib/index.js
CHANGED
|
@@ -75,7 +75,8 @@ function deadline(upstream, timeoutMs, code) {
|
|
|
75
75
|
* Create a rearmable idle watchdog for an async iterator. The timer exists only
|
|
76
76
|
* while {@link IdleWatchdog.next} is outstanding, so consumer think time does
|
|
77
77
|
* not count as provider idle time. The returned signal is stable for the whole
|
|
78
|
-
* call and only notifies; the iterator must observe it to
|
|
78
|
+
* call and only notifies; the iterator must observe it to release the resources
|
|
79
|
+
* of a demand the deadline abandoned.
|
|
79
80
|
*
|
|
80
81
|
* @param upstream - caller cancellation fused into the stable signal.
|
|
81
82
|
* @param timeoutMs - positive finite idle interval in milliseconds.
|
|
@@ -86,13 +87,14 @@ function idleWatchdog(upstream, timeoutMs, code) {
|
|
|
86
87
|
assertTimerDelay(timeoutMs, "idleWatchdog timeoutMs");
|
|
87
88
|
const timeout = new AbortController();
|
|
88
89
|
const signal = upstream === void 0 ? timeout.signal : AbortSignal.any([upstream, timeout.signal]);
|
|
90
|
+
const reason = new TimeoutReason(code, timeoutMs);
|
|
89
91
|
let timer;
|
|
90
92
|
let outstanding = false;
|
|
91
93
|
let disposed = false;
|
|
92
94
|
const arm = () => {
|
|
93
95
|
if (timer !== void 0) clearTimeout(timer);
|
|
94
96
|
timer = setTimeout(() => {
|
|
95
|
-
timeout.abort(
|
|
97
|
+
timeout.abort(reason);
|
|
96
98
|
}, timeoutMs);
|
|
97
99
|
};
|
|
98
100
|
return {
|
|
@@ -102,8 +104,15 @@ function idleWatchdog(upstream, timeoutMs, code) {
|
|
|
102
104
|
if (outstanding) throw new Error("idleWatchdog next is already outstanding");
|
|
103
105
|
outstanding = true;
|
|
104
106
|
arm();
|
|
107
|
+
const expired = Promise.withResolvers();
|
|
108
|
+
const onAbort = () => {
|
|
109
|
+
expired.reject(reason);
|
|
110
|
+
};
|
|
111
|
+
timeout.signal.addEventListener("abort", onAbort, { once: true });
|
|
105
112
|
try {
|
|
106
|
-
return await iterator.next()
|
|
113
|
+
return await Promise.race([iterator.next().finally(() => {
|
|
114
|
+
timeout.signal.removeEventListener("abort", onAbort);
|
|
115
|
+
}), expired.promise]);
|
|
107
116
|
} finally {
|
|
108
117
|
clearTimeout(timer);
|
|
109
118
|
timer = void 0;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -45,9 +45,17 @@ export interface IdleWatchdog {
|
|
|
45
45
|
/** Stable signal aborted by upstream cancellation or this watchdog's timeout. */
|
|
46
46
|
readonly signal: AbortSignal;
|
|
47
47
|
/**
|
|
48
|
-
* Await one iterator demand while the idle timer is armed.
|
|
48
|
+
* Await one iterator demand while the idle timer is armed. The deadline
|
|
49
|
+
* settles the demand even when the awaited work ignores its abort signal.
|
|
49
50
|
* @param iterator - iterator whose next value represents provider progress.
|
|
50
51
|
* @returns the iterator's next result.
|
|
52
|
+
* @throws The {@link TimeoutReason} of this watchdog when the idle interval
|
|
53
|
+
* elapses first. Only that deadline settles the demand: an upstream
|
|
54
|
+
* cancellation reaches the iterator through {@link IdleWatchdog.signal} and
|
|
55
|
+
* never shortens the wait. The abandoned demand stays the caller's to release
|
|
56
|
+
* through that signal; an async generator queues its own return behind it, so
|
|
57
|
+
* callers must not await it. Disposal clears the timer without settling an
|
|
58
|
+
* outstanding demand.
|
|
51
59
|
*/
|
|
52
60
|
next<T>(iterator: AsyncIterator<T>): Promise<IteratorResult<T>>;
|
|
53
61
|
/** Rearm an outstanding demand after transport activity that yields no iterator value; otherwise a no-op. */
|
|
@@ -70,7 +78,8 @@ export declare function deadline(upstream: AbortSignal | undefined, timeoutMs: n
|
|
|
70
78
|
* Create a rearmable idle watchdog for an async iterator. The timer exists only
|
|
71
79
|
* while {@link IdleWatchdog.next} is outstanding, so consumer think time does
|
|
72
80
|
* not count as provider idle time. The returned signal is stable for the whole
|
|
73
|
-
* call and only notifies; the iterator must observe it to
|
|
81
|
+
* call and only notifies; the iterator must observe it to release the resources
|
|
82
|
+
* of a demand the deadline abandoned.
|
|
74
83
|
*
|
|
75
84
|
* @param upstream - caller cancellation fused into the stable signal.
|
|
76
85
|
* @param timeoutMs - positive finite idle interval in milliseconds.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-timeout",
|
|
3
3
|
"description": "Zero-dependency timeout/deadline primitive: clampTimeout, deadline, timeoutOf, TimeoutReason (timing + classification only, no termination)",
|
|
4
|
-
"version": "0.2.1-alpha.
|
|
4
|
+
"version": "0.2.1-alpha.3",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
],
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@deepseek-ai/cordis": "~4.0.5-alpha.
|
|
30
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.2"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@deepseek-ai/cordis": "~4.0.5-alpha.
|
|
33
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.2"
|
|
34
34
|
}
|
|
35
35
|
}
|