-
-
Notifications
You must be signed in to change notification settings - Fork 155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
socket.close fired but not 'onClose' callback from useServer #152
Comments
Hmm, the Lines 107 to 118 in c0b171e
and then the Lines 731 to 740 in c0b171e
Could you share a simple repro? Maybe some of the cleanup actions stall. |
Hum, I think it's related to my async iterator on my subscription (I will share a repo if this still not help). This code calls useServer(
{
...
schema,
roots: {
subscription: {
async *allChannelEvent() {
logger.info("allChannelEvent: ");
try {
for (const hi of ["Hi", "Bonjour", "Hola", "Ciao", "Zdravo"]) {
yield {
allChannelEvent: {
channelId: "$ID",
type: "IS_TYPING",
userId: "$ID",
__typename: "ChannelEventResult"
}
};
}
} catch (e) {
console.log(`Error allChannelEvent: ${e}`);
} finally {
console.log("Finally allChannelEvent");
}
}
}
...
}
) This code not fire 'onClose' useServer(
{
...
schema,
roots: {
subscription: {
async *allChannelEvent() {
logger.info("allChannelEvent: ");
try {
const iterator = pubsub.asyncIterator("$ID");
let next;
while ((next = await iterator.next()).done === false) {
yield {
allChannelEvent: next.value
};
}
} catch (e) {
console.log(`Error allChannelEvent: ${e}`);
} finally {
console.log("Finally allChannelEvent");
}
}
}
...
}
) The pubsub code is similar to this repository. |
What version of graphql.js and Node.js are you using? |
Can you check if the Also, why use the const iterator = pubsub.asyncIterator('$ID');
for await (const value of iterator) {
yield {
allChannelEvent: value,
};
} |
Any news @c4c1us? |
Hi, I'm testing your code above. |
Hi again, @n1ru4l Node v14.15.1 / GraphQL 14.5.8 @enisdenjo
|
might be related to this graphql/graphql-js#2983 (Note: i dis not verify, just saw the issue and it seems this might be related) |
@c4c1us well, the for loop must break after returning the iterator for the teardown to work... As you mentioned in #152 (comment), if the loop breaks, |
@n1ru4l I downgrade to 14.10.1, It didn't fix the issue. @enisdenjo I change my subscription and put this : ...
subscription: {
allChannelEvent: () => ({
async return() {
console.log("RETURN");
await sleep(1000);
},
async throw() {
console.log("THROW");
await sleep(1000);
},
async *[Symbol.asyncIterator]() {
const iterator = pubsub.asyncIterator(
"$ID"
);
for await (const value of iterator) {
yield {
allChannelEvent: value
};
}
}
})
}
... I see in the
So in my code, the I tried this too (without the function returning the value): ...
subscription: {
allChannelEvent: {
async return() {
console.log("RETURN");
await sleep(1000);
},
async throw() {
console.log("THROW");
await sleep(1000);
},
async *[Symbol.asyncIterator]() {
const iterator = pubsub.asyncIterator(
"$ID"
);
for await (const value of iterator) {
yield {
allChannelEvent: value
};
}
}
}
... I'm new to iterator & generator but I can't see what I'm doing wrong here unfortunatly. |
Just calling *Copied from AsyncIterator recipe import { createClient, SubscribePayload } from 'graphql-ws';
const client = createClient({
url: 'wss://iterators.ftw/graphql',
});
function subscribe<T>(payload: SubscribePayload): AsyncIterableIterator<T> {
let deferred: {
resolve: (done: boolean) => void;
reject: (err: unknown) => void;
} | null = null;
const pending: T[] = [];
let throwMe: unknown = null,
done = false;
const dispose = client.subscribe<T>(payload, {
next: (data) => {
pending.push(data);
deferred?.resolve(false);
},
error: (err) => {
throwMe = err;
deferred?.reject(throwMe);
},
complete: () => {
done = true;
deferred?.resolve(true);
},
});
return {
[Symbol.asyncIterator]() {
return this;
},
async next() {
if (done) return { done: true, value: undefined };
if (throwMe) throw throwMe;
if (pending.length) return { value: pending.shift()! };
return (await new Promise<boolean>(
(resolve, reject) => (deferred = { resolve, reject }),
))
? { done: true, value: undefined }
: { value: pending.shift()! };
},
async return() {
dispose();
return { done: true, value: undefined };
},
};
}
(async () => {
const subscription = subscribe({
query: 'subscription { greetings }',
});
// subscription.return() to dispose
for await (const result of subscription) {
// next = result = { data: { greetings: 5x } }
}
// complete
})(); |
I understand that calling the return does not break the loop, but in my example, the |
I gonna search again, thanks for help btw. |
I suggest reading on async iterators first. I find this article quite good: https://javascript.info/async-iterators-generators. In essence the Line 736 in 77a2981
|
I found my mistake ! As you said I should use the async iterator of the Why ? Because with Apollo Server you have to "yield" only the Thanks for your help and patience ! 🙏 |
Glad you got it working! 🎉 |
Hi,
I was trying to fire the
onClose
callback fromuseServer
by closing my tab on Chrome. The function is never fired, butsocket.on("close",..)
is.Is this a bug or a normal behaviour ?
The text was updated successfully, but these errors were encountered: