mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-01 21:20:44 +00:00
fix(sdk): settle pending next() promise in Stream.return() to prevent hangs (#2981)
* fix(sdk): settle pending next() promise in Stream.return() to prevent hangs * test(sdk): add regression tests for Stream.return() pending-promise cleanup
This commit is contained in:
parent
b82ad2bd4c
commit
ed6f9e056e
2 changed files with 28 additions and 0 deletions
|
|
@ -71,6 +71,13 @@ export class Stream<T> implements AsyncIterable<T> {
|
|||
|
||||
return(): Promise<IteratorResult<T>> {
|
||||
this.isDone = true;
|
||||
// Settle any pending next() promise so awaiters don't hang forever.
|
||||
if (this.readResolve) {
|
||||
const resolve = this.readResolve;
|
||||
this.readResolve = undefined;
|
||||
this.readReject = undefined;
|
||||
resolve({ done: true, value: undefined });
|
||||
}
|
||||
if (this.returned) {
|
||||
this.returned();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,6 +233,27 @@ describe('Stream', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('return() cleanup', () => {
|
||||
it('settles a pending next() promise so awaiters do not hang', async () => {
|
||||
// Consumer starts awaiting before any value is enqueued.
|
||||
const pending = stream.next();
|
||||
// External code cancels the iterator (e.g., timeout race, manual close).
|
||||
await stream.return();
|
||||
// The original pending promise must resolve cleanly with done:true.
|
||||
const result = await pending;
|
||||
expect(result).toEqual({ done: true, value: undefined });
|
||||
});
|
||||
|
||||
it('return() invokes the optional returned callback', async () => {
|
||||
let called = 0;
|
||||
const s = new Stream<string>(() => {
|
||||
called++;
|
||||
});
|
||||
await s.return();
|
||||
expect(called).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Iteration Restrictions', () => {
|
||||
it('should only allow iteration once', async () => {
|
||||
const stream = new Stream<string>();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue