Skip to content
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

Websocket are blocking HttpServer shutdown #28466

Open
hakkanicko opened this issue Mar 11, 2025 · 0 comments
Open

Websocket are blocking HttpServer shutdown #28466

hakkanicko opened this issue Mar 11, 2025 · 0 comments

Comments

@hakkanicko
Copy link

hakkanicko commented Mar 11, 2025

Version: Deno 2.2.3

Context

I made a websocket proxy with Deno. And when I try to stop it, the server won't stop if there is one active WebSocket.
Closing the websocket won't fix the issue.

How to reproduce it

Create two files:

// proxy.ts

const abortController = new AbortController();

function websocketProxy(request: Request, _info: any) {
  if (request.headers.get("upgrade") !== "websocket") {
    return new Response("Not a websocket request", { status: 400 });
  }
  const { response, socket } = Deno.upgradeWebSocket(request);

  const remoteSocket = new WebSocket("http://localhost:3031");

  socket.addEventListener("message", (event) => {
    remoteSocket.send(event.data);
  });

  remoteSocket.addEventListener("message", (event) => {
    socket.send(event.data);
  });

  socket.addEventListener("close", () => {
    remoteSocket.close();
  });

  remoteSocket.addEventListener("close", () => {
    socket.close();
  });

  socket.addEventListener("error", (_event) => {
    remoteSocket.close();
  });

  remoteSocket.addEventListener("error", (_event) => {
    socket.close();
  });

  abortController.signal.addEventListener("abort", () => {
    socket.close(1000, "aborted");
    remoteSocket.close(1000, "aborted");
  });

  return response;
}

function runnerAroundTheServer() {
  const runningServer = Deno.serve({
    signal: abortController.signal,
    port: 3030,
  }, websocketProxy);

  return {
    async shutdown() {
      abortController.abort();
      await runningServer.finished;
    },
  };
}

const runningApp = runnerAroundTheServer();

Deno.addSignalListener("SIGINT", runningApp.shutdown);
Deno.addSignalListener("SIGTERM", runningApp.shutdown);
// websocketEcho.ts
function reverseMessageServer(request: Request, _info: any) {
  if (request.headers.get("upgrade") !== "websocket") {
    return new Response("Not a websocket request", { status: 400 });
  }
  const { response, socket } = Deno.upgradeWebSocket(request);

  socket.addEventListener("message", (event) => {
    socket.send(event.data.toString().split("").reverse().join(""));
  });

  return response;
}

Deno.serve({
  port: 3031,
}, reverseMessageServer);

Run deno run -A proxy.ts and deno run -A websocketEcho.ts

Use a websocket client to connect to the proxy, like websocat ws://localhost:3030/

Try to quit the proxy.ts using CTRL+C

Expected behavior

The server should stop. And the socket and remoteSocket should close.

Actual behavior

  • remoteSocket closes
  • socket doesn't close
  • the server doesn't stop
  • the socket closes if you try to send a message to the proxy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant