No port protection if application is launched twiced
- Version: 13.5.1 (but confirmed source code was not improved in the latest for this issue)
- Target: Windows (Windows 11) / MacOS (M Series)
What is happening is that during app startup, Electron Dot Net will inspect open ports to use as a setting for spawning the back-end server. There is a brief window between when the port number is selected, and when the back-end app actually starts up to utilize that port. If another app were to also start up during this time, then you get multiple instances attempting to spawn a back-end server using that same port and configuration. This results in a collision of port usage, causing the app to either crash or lock up.
Steps to Reproduce:
- Launch built electron dot net application
- Quickly launch a second instance
- Note JavaScript exception that appears
You are right - there is a race for which you're not the first to discover. Of course, I had seen this as well when redoing the lifetime control. I had thought about it and concluded not to spend any time on it. Reasons:
- It has been like that for all the years with little impact
- Typically (and by default) you have 'single-instance' enabled
- The chance of collision with the port-selection of a different app is negligible on a desktop OS
- There is no simple and straightforward solution
Now, it's a matter of how you weigh out these against each other, which should start by thinking about all the possible ways for fixing this, like global mutex or other kinds of locking, or some tricky handshake protocol, etc. None of those fixes (at least I have no simple idea) is trivial, which means that you probably don't get it perfectly right at the first time, so that bugfix would have a hight risk of causing trouble for all - and for what? For fixing an issue that nobody ever had in the first place?
In the majority of use cases, users will want and leave "Single-Instance" enabled (rather create additional window than another launch. For the few cases where parallel processes are actually intended, it's probably better when the consuming users implement that themselves, as they can choose the way which is most suitable for their case.
So far my own thoughts. You are welcome to submit a fix for thiss. Yet it should be really solid...
I think this is rather exotic. I have never seen a collision. One way to mitigate this is to avoid having a fixed port at all. This way you'd always get a free port.
So yes feel free to contribute an improved version but if there is no movement on this issue I'd close it.
I had a similar issue, and I solved it by ensuring that only a single instance of the app is running at the same time. For that, I check the running processes, and only start a new process if it isn't already running. Otherwise, I send the startup args to that already running process via a simple named pipe. The main process then spawns a new (sub) process with a new window and the given args.
@AeonSake
Why? Electron.NET already does that - pretty similar to your recipe:
https://github.com/ElectronNET/Electron.NET/blob/2c82206c6242ca44ff92cba7843bedc256e025e2/src/ElectronNET.Host/main.js#L97-L122
And it's the default behavior:
https://github.com/ElectronNET/Electron.NET/blob/2c82206c6242ca44ff92cba7843bedc256e025e2/src/ElectronNET/build/ElectronNET.Core.props#L7-L10
Why?
Just in general, not necessarily for electron as host. I was not aware how exactly electron handles this case, though. How is the new window and session spawned?
Just in general, not necessarily for electron as host.
Ah, sure!
How is the new window and session spawned?
Did you look at the snippet above?
Did you look at the snippet above?
Yes, but it's not fully clear to me. Does this mean it is fully handled on the electron side? How are start args communicated to the ASP.NET process?
Yes, but it's not fully clear to me. Does this mean it is fully handled on the electron side? How are start args communicated to the ASP.NET process?
You do the same/similar on the .net side:
https://github.com/ElectronNET/Electron.NET/blob/2c82206c6242ca44ff92cba7843bedc256e025e2/src/ElectronNET.API/API/App.cs#L916-L918
It's independent from the nodejs code.