Building with SSR false starts (and doesn't close) listeners
In my app I create a WebsocketServer on Port 3001.
If I run
npm run build
with default SSR setting (ssr: true
) everything works like a charm.
However, turning off ssr
, the WebsocketServer gets started and not closed => EADDRINUSE error. Cannot run dev
or start
afterwards.
After forcefully terminating the process, I can run start
with the built files and it works.
Any suggestions on how to avoid this?10 Replies
I found the problem.
In the build step for
spaClient
a shell is spawned as a child_process. This shell then runs the vite command, creating a subprocess within a child_process. On kill of the shell, the SIGTERM does not get forwarded into the Vite process, therefore there is no graceful shutdown.
I've created a somewhat unsatisfying PR against the solid-start repo. https://github.com/solidjs/solid-start/pull/1033
Unsatisfying in that it only fixes the issue for Linux afaict.
Anyone reading this who would like to help out with this PR please feel free to contribute 🙏Left a suggestion on the PR.
Thank you! I saw it and that's kind of what I was hoping for 🙂 Great work. Would you like to open a new PR from your repo and I'll close the current one as superseded?
Sure but If you could help me understand / reproduce the issue that would be cool. I don't quite know how to reproduce EADDRINUSE on my Windows machine. Any hint/steps woulb be nice. Like where do I need to add the long running listener or was this referring to vite?
Of course, I think with these simple steps it should be easily reproducible:
1. install
ws
package
2. in entry-server.tsx
add this code:
This should already do it.
With this in place, dev
works normally actually. So when you interrupt the process, the port should be released. But running build
spawns the process that never ends. From here, start
, dev
or even a new build
all fail.
In my case we have the Socket logic in a different file and import it into entry-server
but I guess for an easy reproduction this step is not relevant.
Edit: there probably are even easier ways to reproduce this behavior, I'm just going with what caused the issue in our case.
Edit2: I forgot to mention but it should be obvious: set solid({ ssr: false })
in vite.config
The whole picture comes together when you actually have a graceful shutdown in place. I'm not sure what the default behavior here is, actually. But again for this simple scenario it should suffice to add
New development: the PR was just now merged as is. This does satisfy my specific use-case. But I would like to encourage you to go ahead to open a separate PRThats good, better then waiting and I want to reproduce the error first. Thanks for the detailed steps I will try it out.
Tbh I wish I could have brought a solution like yours to the table, but I just don't feel comfortable enough to go beyond a single digit line change. 😄 I think your work would really bring a positive outcome for countless other devs who might face this issue 🙂 Regardless of the platform they're using
My suggestion has a similar problem which I expected after seeing the server initialization. Building works but the websocket server will block until its explicitly closed (ctrl+c). 🤣
Regarding this:
Edit: as a side note I was also able to "fix" this by changing the stdio option. But in this specific case they bring their own bugs
Was this with detached set to true? I didn't notice any difference by just changing stdio.
Anyway... in this specific case I don't see any other solution beside what you did and try to terminate all related processes. Only thing I see avoiding this is providing an index.html in the project root so the build process does not run entry-server.No this was with settings "as-is", without detached option.
Unfortunately, this doesn't actually fix the problem on Windows, though. I also thought avoiding a shell intermediate process would probably be the best way to go, but seeing that
spaClient
is the only build option that has that, I assumed there's a reason for why it is needed. :/ If there is a way along the lines you propose, I guess it would be the best after all
Edit: ahh wait, I misunderstood. I meant avoiding the shell like you did in your PR. I guess for a proper server build to go through, there is no way to circumvent entry-server
it's basically the prime (and only) entrypoint where you can initialize stuff on the server. Without that it would most likely break the functionality of the server runtime altogether.
Btw, unrelated:
I just wanted to quickly thank you for being such an active contributor. I noticed that you had your hands in a lot of changes recently and I, as a surrogate for the whole community, would like to voice my appreciation 🙂 💪Aww I don't feel like I have done much but totally appreciate the kind words. 😄
Regarding the current spa build process. The longer I think about it and look at the code it's starting to seem insane to call the server (through vite dev or directly) to generate the index.html. At the end its just the entry point for the client build (single script tag pointing to entry-client). I feel like I am missing something but it looks to me as if generating the index.html from a hardcoded string would be the same. It doesn't seem like its creating anything dynamically or using something provided by the user. nvm I kind of understand now why it is like that.
I am also not too sure about creating the websocket server in entry-server but thats probably me not knowing the use case. My first thought would be to run it separately or trying to run it as a middleware if possible.