How can I gracefully stop a uWebSockets server?

2.3k views Asked by At

How could I exit from the run() call in the official example? For example after receiving a signal.

uWS::SSLApp({

    /* There are tons of SSL options */
    .cert_file_name = "cert.pem",
    .key_file_name = "key.pem"

}).onGet("/", [](auto *res, auto *req) {

    /* Respond with the web app on default route */
    res->writeStatus("200 OK")
       ->writeHeader("Content-Type", "text/html; charset=utf-8")
       ->end(indexHtmlBuffer);

}).onWebSocket<UserData>("/ws/chat", [&](auto *ws, auto *req) {

    /* Subscribe to topic /chat */
    ws->subscribe("chat");

}).onMessage([&](auto *ws, auto message, auto opCode) {

    /* Parse incoming message according to some protocol & publish it */
    if (seemsReasonable(message)) {
        ws->publish("chat", message);
    } else {
        ws->close();
    }

}).onClose([&](auto *ws, int code, auto message) {

    /* Remove websocket from this topic */
    ws->unsubscribe("chat");

}).listen("localhost", 3000, 0).run();
1

There are 1 answers

3
Filip Procházka On

In a documentation, there is written following:

Many users ask how they should stop the event loop. That's not how it is done, you never stop it, you let it fall through. By closing all sockets, stopping the listen socket, removing any timers, etc, the loop will automatically cause App.run to return gracefully, with no memory leaks.

Because the App itself is under RAII control, once the blocking .run call returns and the App goes out of scope, all memory will gracefully be deleted.

So it means you have to release every source inside of the function. So e.g. this:

    void testThread() {
        std::this_thread::sleep_for(15s);
        us_listen_socket_close(0, listen_socket);
    }

    int main()
    {
        std::thread thread(testThread);
        uWS::App app;
        /* Very simple WebSocket broadcasting echo server */
        app.ws<PerSocketData>("/*", {
            /* Settings */
            .compression = uWS::SHARED_COMPRESSOR,
            .maxPayloadLength = 16 * 1024 * 1024,
            .idleTimeout = 10,
            .maxBackpressure = 1 * 1024 * 1204,
            /* Handlers */
            .open = [](auto* ws, auto* req) {
                /* Let's make every connection subscribe to the "broadcast" topic */
                ws->subscribe("broadcast");
            },
            .message = [](auto* ws, std::string_view message, uWS::OpCode opCode) {
            },
            .drain = [](auto* ws) {
                /* Check getBufferedAmount here */
            },
            .ping = [](auto* ws) {

            },
            .pong = [](auto* ws) {

            },
            .close = [](auto* ws, int code, std::string_view message) {
                std::cout << "Client disconnect!" << std::endl;

                /* We automatically unsubscribe from any topic here */
            }
            }).listen(9001, [](auto* token) {
                listen_socket = token;
                if (token) {
                    std::cout << "Listening on port " << 9001 << std::endl;
                }
                });
            app.run();

            std::cout << "Shutdown!" << std::endl;

And after calling testThread, the server should exit (if no client is connected, otherwise, you should also disconnect connected clients (sockets)) and continue after run() line. After disconnect the client, my output is following:

Listening on port 9001

Client disconnect!

Client disconnect!

Client disconnect!

Client disconnect!

Client disconnect!

Client disconnect!

Shutdown!