-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Node.js cannot receive signals like SIGTERM #550
Comments
It's not just Node. And yes, in a lot of cases, you'd like to put some init system. Many people have suggested |
After a tremendous amount of research and testing, I've finally gotten to the bottom of what's going on. In case anyone else encounters a similar issue, I've documented what I've learned… It turns out that Node.js running as PID 1 handles signals like
The After some further testing, I discovered that as soon as any asynchronous code began executing after the I finally tracked the actual problem down to Prisma, which prevents apps from gracefully shutting down. This is discussed here: prisma/prisma#2917. I was able to verify that Prisma is calling |
Thanks for the update! It surely will help others. |
It seems like an issue with the python distroless image at least. Any ideas?
All signals to the python process are ignored in this case. |
It works in my testing.
In another terminal,
Then in the original terminal,
OTOH, in #550 (comment), the NodeJs doc clearly states
|
It doesn't seem to work outside of the container, is what I meant. Neither |
Still, this is not true.
In another terminal, I do
And in the original terminal,
|
SIGINT works here as well, but not SIGTERM. Is that expected? If I run it outside of distroless, it does quit upon receiving SIGTERM. |
At least SIGKILL (yes, I did confirm) and SIGINT work. I am not a Python dev, so I don't know about what's with SIGTERM. But this is not a Distroless issue. The behavior is consistent outside Distroless. Using the official Docker Hub
In another terminal,
|
SIGKILL will work because the OS hard kills the process. SIGINT works I believe because docker itself installs an INT handler, so you can do |
I don't know what kind of INT handler you are talking about that is installed in which process at which level, but it's not that a process can modify another running process to magically install some signal handler to do something. In fact, no OS allows one process to modify another. A process can only send signals to others. What is clear is that, the
If you are saying that the Docker runtime doesn't just allow sending SIGTERM to a process in a container running on its Docker runtime, then that's a Docker runtime problem. (However, I don't think that is the case.) But then, I found out the correct reason: https://hackernoon.com/my-process-became-pid-1-and-now-signals-behave-strangely-b05c52cc551c
|
I meant when you do But it's interesting that python itself seems to handle SIGINT as pid 1 but ignores SIGTERM completely. I still can't explain why that's the case - I guess this is something baked into python. Doing this, I can get it to respond to SIGTERM:
|
Just felt I wanted add an update to prevent any further dissemination of misinformation or any possible confusion for posterity who are not familiar with signal handling.
I should clearly point out that this is not true. Even if the
See the linked article in #550 (comment). |
Thanks for the info, but I wasn't trying to disseminate misinformation. Just trying to understand where the issue lies - whether with distroless or elsewhere. The linked article itself I found a bit confusing. It states that "it ignores any signal with the default action.". This makes it sound like the process is doing something special to ignore these signals. But all that is happening is that the default actions for those signals are not installed by the kernel for PID 1 as a special case. In summary:
I believe both Java and golang seem to handle SIGTERM just fine as PID 1, so it's Python just not setting up its own handler for it, and relying on the OS default action to be installed. In my mind, this means it would make some sense for distroless Python to do something special to handle SIGTERM when running python as pid 1. Otherwise people will run into issues with it not stopping properly such as in K8s, unless they take special action. |
IMO, this is out of the scope of Distroless. PID 1 means a lot on Linux and is supposed to take a lot of responsibilities including adopting orphan processes, reaping zombie processes, handling signals, etc. And the way you want to deal with these issues highly depends on your situation. People suggest different ideas and approaches for resolving these issues, and if you google, you'll find a lot of articles about what they think is their problem and what would be the best solution in their situation. There are many different ways and tools. For some, directly running your application process as PID 1 just works, and they think it's perfectly fine; no need for the usual PID 1 responsibilities. If your long-running process can spawn child processes and has a possibility of zombie processes starving all PIDs, perhaps deploying a full init system may be what you want, which can also be a solution to your python SIGTERM issue as well. But some folks don't like this setup but argues that running a single process in a container is the best practice which lets the container runtime manage the lifecycle of an application; with multiple processes, there's added complexity to properly handle app lifecycle. And in your situation, you only seem to care about whether SIGTERM terminates |
Currently, the Node.js distroless container runs the Node.js process as PID 1:
According to Node.js's best practices:
So basically, Node.js apps won't receive
SIGTERM
,SIGINT
, etc. when running insidegcr.io/distroless/nodejs
.The text was updated successfully, but these errors were encountered: