-
Notifications
You must be signed in to change notification settings - Fork 579
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
Unreachable code after infinte loop inside generic function "http#serve" #142
Comments
Currently there is indeed no way of closing the listener. It would be a good idea to revamp the HTTP module with more careful design (and possibly emulating part of implementation from Go) (a few contributors have expressed interest on this) |
Yep, seems like this isn't possible right now. I was looking for a way to implement a server.close() equivalent in pogo, to gracefully stop accepting requests and allow the process to exit with a status code of zero (success). This is needed for production deployments, where killing a process from the outside can cause all kinds of problems. |
For people who want this feature immediately, it is possible to add Lines 60 to 69 in bef7ba1
(this piece of code immediately tries to wait for a next accept when the previous one is handled)and also breaks from Lines 74 to 85 in bef7ba1
(This is for sure not an elegant structure. I hope someone could take some time to improve this while still keeping the capability of doing async iterator for request handling.) |
Maybe I could do something along the lines of: class App {
async handleRequest(request) {
// ... do stuff with request ...
}
close() {
this._shouldClose = true;
}
async start() {
const server = http.serve('localhost:1234');
for await (const request of server) {
await this.handleRequest(request);
if (this._shouldClose) {
break;
}
}
}
} But I haven't tested it. And I think that would wait for a request to come in before closing, which seems bad. |
I'm testing a hack to support closing the server, preferably something with very few and simple changes. For example this is a way you could run the server and handle it closing: const generatorStopper = {stop: null}
const requestGenerator = http.serve(this.address, generatorStopper)
for await (const req of requestGenerator) {
if (req === false) {
log('Server has closed')
break
}
// else handle the request
} Where this would be called to stop it: generatorStopper.stop() And how the serve generator function could implement it (tested and works). I'm no TypeScript programmer, so please excuse my dirty JavaScript... :P export async function* serve(addr: string, generatorStopper) {
const listener = listen("tcp", addr);
const env: ServeEnv = {
reqQueue: [], // in case multiple promises are ready
serveDeferred: deferred()
};
// Routine that keeps calling accept
let handleConn = (_conn: Conn) => {};
let scheduleAccept = () => {};
const acceptRoutine = () => {
scheduleAccept = () => {
listener.accept().then(handleConn).catch(()=>{/*ignore*/});
};
handleConn = (conn: Conn) => {
serveConn(env, conn); // don't block
scheduleAccept(); // schedule next accept
};
scheduleAccept();
};
acceptRoutine();
if (typeof generatorStopper == 'object' && 'stop' in generatorStopper) {
generatorStopper.stop = (() => {
env.serveDeferred.resolve(false);
});
}
// Loop hack to allow yield (yield won't work in callbacks)
while (true) {
if (await env.serveDeferred.promise === false) {
break
}
env.serveDeferred = deferred(); // use a new deferred
let queueToProcess = env.reqQueue;
env.reqQueue = [];
for (const result of queueToProcess) {
yield result;
// Continue read more from conn when user is done with the current req
// Moving this here makes it easier to manage
serveConn(env, result.conn, result.r);
}
}
listener.close();
yield false;
} Of course I modified a few other places in the code to support the new "false" type. E.g: interface Deferred {
promise: Promise<{}>;
resolve: (arg) => void;
reject: () => void;
} And the
All I'm saying is that there are solutions to implement a way to close the server and it is not hard to do. But since I'm no TypeScript programmer I'm not really going to contribute with any pull requests any time soon, I don't have the energy/health to get involved in this yet. EDIT: Added this text: import { BufReader, BufState, BufWriter } from "https://deno.land/x/io/bufio.ts";
import { TextProtoReader } from "https://deno.land/x/textproto/mod.ts";
import { STATUS_TEXT } from "https://deno.land/x/http/http_status.ts";
import { assert } from "https://deno.land/x/testing/asserts.ts"; Add rest of changes and then import that file instead in your project: import * as http from "httpServer.ts" |
Code in this line never run and listener never closing.
The text was updated successfully, but these errors were encountered: