python-microscope / microscope

Python library for control of microscope devices, supporting hardware triggers and distribution of devices over the network for performance and flexibility.
https://www.python-microscope.org
GNU General Public License v3.0
69 stars 41 forks source link

device_server: Add alternative ways to terminate cleanly #202

Open dstoychev opened 3 years ago

dstoychev commented 3 years ago

As it stands, the device server can only be properly shutdown by catching KeyboardInterrupt and IOError exceptions. It will be nice to have an alternative way, e.g. by reading a message from STDIN.

dstoychev commented 3 years ago

Although I still think it'd be nice, for example, to send "exit" to the STDIN to stop the device server, in practice this proved to be more elaborate than I anticipated. The problem, of course, is Windows. Not only does it not work with signals the same way that POSIX does, but select() also doesn't work for the STDIN. There doesn't seem to be a simple solution, let alone an elegant one. I tend towards closing this issue.

carandraug commented 3 years ago

The device server output is not really an interactive environment, so having it reading "exit" from STDIN to exit the device server seems odd to me. Waiting for a signal/interrupt is pretty standard is pretty common and I would argue the least surprising.

Is the aim of this making it easier to "discover" the way to exit the device server? If so, what about printing something like "device server started. Press Ctrl+C to exit." at the start? I have also seen that in a couple of programs.

dstoychev commented 3 years ago

No, the problem is that by accepting only CTRL+C events the device_server module effectively becomes a console application. So any attempts to run a device_server silently in the background are defeated by the necessity to have a console window open and visible. At least on Windows.

If the device_server were able to recognise other signals, then it would be possible to run it as a true headless application in Windows. There is no need to use STDIN, I just suggested it as a quick solution. Much better would be to have some sort of IPC interface, ideally something common between POSIX and Windows, e.g. named pipe or even a socket.

carandraug commented 3 years ago

No, the problem is that by accepting only CTRL+C events the device_server module effectively becomes a console application. So any attempts to run a device_server silently in the background are defeated by the necessity to have a console window open and visible. At least on Windows.

Definitely not true on non-Windows platforms. You can send SIGKILL and SIGTERM to the process on. And even on windows, it should be possible to run device-server as a Windows service (that's what the microscope.win32 module is meant to do and I think that's what they were using at Diamond).

If the device_server were able to recognise other signals, then it would be possible to run it as a true headless application in Windows.

Is the goal here to have another program start and stop device server, or is the goal to automatically start the device server without user interaction?

dstoychev commented 3 years ago

The goal is to terminate a device_server process gracefully, so that it shutdown down properly all of its servers. On Windows, this is only possible when there is a console attached to the process, which I find too restrictive, hence this issue.

In practice there are many ways to circumvent this restriction. Using the service manager, as in the win32 module, is one such way. I haven't tried it, though, so I am not familiar with the disadvantages of this method, but creating and installing an entire service seems like the wrong approach to me.

The objective here is for the device_server to detect when it needs to terminate on Windows (POSIX already has signals). Besides the IPC suggested above, this could probably be achieved with a simple watchdog or maybe there is an obscure Windows-specific alternative to signal handling.

iandobbie commented 3 years ago

On windows the RIGHT WAY is to use the services infrastructure. We had this working with the DSP at Diamond but it was not implemented for microscope. It would be a real win if it was as the current approach is to have batch files which users need to double click on to start a shell and then the device-server. On windows the POSIX stuff is terrible in my experience. On linux I would run it from init or systemd for a setup like diamond where you just want it to run. Dont know how I would do it on macOS.