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

Graceful shutdown on windows without installing as service #3809

Closed
choofy opened this issue Jan 24, 2023 · 4 comments
Closed

Graceful shutdown on windows without installing as service #3809

choofy opened this issue Jan 24, 2023 · 4 comments
Assignees

Comments

@choofy
Copy link

choofy commented Jan 24, 2023

Feature Request

As software developer who wants to integrate the nats executable in his own product, so that his own product is "batteries included" without the user having to install Nats separately, I want to be able to stop Nats gracefully from my product, so that I do not see messages dropped anymore when I kill Nats on windows.

On Linux, it is possible to kill a process gracefully using signals, but that does not work on windows.

  • There already is an implementation to use ctrl-c to stop gracefully (Shutdown on Ctrl+C #1186), but it is difficult to sent ctrl-c to a process in windows, and when I succeed, it also kills my own process which is not what I want.
  • There is an approach to install Nats as a windows service (Strategy for signaling config reload on Windows #521), but that is not what I want. I just want to run Nats as long as my application runs -- I do not want to install a windows service that is also there when my application stops or crashes and leaves garbage around in windows.

Use Case:

Graceful stop of Nats on windows without having to install it as a service.

Proposed Change:

  • When started, create a .run file next to the .pid file (with configurable location, like --run-file). Nats watches this file. When deleted, nats stops itself gracefully. When stopped, nats deletes this file (when still prsent).

Who Benefits From The Change(s)?

  • Fans of Nats that want to integrate Nats in their windows product to offer the end user the best possible batteries-included experience.

Alternative Approaches

  • Accept commands via stdin (like "stop\n").
  • Accept a pid as argument to --signal stop: on windows (like it is on linux), and then use the same mechanism already in use on windows to signal a service application to get this signal to the application. This would be my prefered solution, but now that I found the source code for ProcessSignal, I see that this mechanism flly relies on the windows service funtionality of stopping and reconfiguration, so this is not realistic to implement without having to use services.
@BentTranberg
Copy link

I'm not a NATS developer. Just a developer using NATS.

Can this be solved with any predefined messages in NATS?

so that I do not see messages dropped anymore when I kill Nats on windows.

What exactly do you mean when you say you kill NATS on Windows? How do you start, run and stop NATS? Do you run it as a child process within your app? Are messages also dropped if you just close a NATS that was started manually? Which programming language and runtime platform is this? Asking in case me or anybody else out there should try to find a solution for the situation - a solution that does not involve modifying NATS.

I think the mechanism described in "Proposed Change" looks like the kind of hack we'd rather not see in a professional product like NATS, but the --signal stop also working for NATS in console mode would be nice.

NATS server could also hold on to a named mutex while running, and that mutex would only be created if a parameter like --mutex myMutex is supplied. I guess this would be a Windows only mechanism. Utilities or your own programs could then wait for the mutex to be released at the termination of NATS. This would only be in effect if that parameter is specified, so would not jeopardize existing deployments of NATS.

@tbeets
Copy link
Contributor

tbeets commented Feb 2, 2023

Understand the functionality desire @choofy .

The root issue re-emerges at some regularity. Windows, not being UNIX, fundamentally has a different architecture (multiple actually) for process signaling.

Console applications in Windows (as NATS is generally when not configured as a Windows service) suffer from intractable "console group limitations" mentioned in root issue.

If running NATS as a Windows service doesn't work for your application, recommendation is to wrap NATS and execute as an embedded server. Here's an example. In this manner, you have a pointer to the server and can manage lifecycle in a way that fits your specific need (including bespoke up/down/reload mechanism, etc. that you implement).

@tbeets
Copy link
Contributor

tbeets commented Feb 2, 2023

Recommendation to leverage existing feature to install NATS server as a Windows service or implement application-specific server lifecycle using NATS embedded server technique.

@tbeets tbeets closed this as completed Feb 2, 2023
@choofy
Copy link
Author

choofy commented Feb 3, 2023

Dear Todd,

Thank you for yor reply and code examples. It still feels a bit awkward that in order to gracefully stop an application on windows, I have to 'hack around' and create my own loader (basically, create my own application that uses your nats implementation -- when I understand you correctly).

Your proposed solution would be acceptable to me if Nats would, in addition to the executables, also officially build and publish .so/.dll files so that I would not have to do that myself.

But your current solution is not something that works for me, I just want to use NATS, I do not want to develop it.

As @BentTranberg mentions, it would be expected from a professional product like NATS that the --signal stop also works on standalone windows programs (without services) like it does on Linux. It feels too easy to get away with that by just saying "create your own copy of Nats and embed it in your software".

How about his proposal of using a Mutex for that on windows?
I like that proposal. No messing around on file systems. Just:

  • Have my application create a mutex
  • Have my application pass the name via --mutex or --lifecyclemutex to NATS
  • Have a NATS goroutine try to acquire the mutex. When it has, it gracefully stops.
  • My application can release the mutex when it want NATS to stop.

All it requires is a NATS goroute that awaits the mutex and initiates the graceful stop. Seems like little more than a one-liner.

I believe this is a rather elegant solution, with almost no code changes, that would greatly enhance the use cases for Nats. Not many people will create an "embedded server" themselves, that just is too much hassle for everyone that is not really familiar with go.

@tbeets Although you already closed the ticket, please (re)consider this suggestion.

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

4 participants