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

Add ability to send arbitrary UNIX signals to processes: #477

Merged
merged 11 commits into from
Aug 19, 2014
Merged

Add ability to send arbitrary UNIX signals to processes: #477

merged 11 commits into from
Aug 19, 2014

Conversation

msabramo
Copy link
Contributor

  • Extend the Process class to handle non-killing signals
  • Expose this via the XML-RPC API
  • Add supervisorctl signal command

This is an update of PR #228 and hopefully moves the ball forward on #179, #53, etc.

Cc: @squeed, @Weebly, @mnaberez, @sontek

* Extend the Process class to handle non-killing signals
* Expose this via the XML-RPC API
@msabramo
Copy link
Contributor Author

I just fixed a few Python 3 issues.

@msabramo
Copy link
Contributor Author

Here's an example of using the RPC interface from IPython:

❯ ipython
Python 2.7.6 (default, Nov 11 2013, 13:08:06)
Type "copyright", "credits" or "license" for more information.

IPython 2.0.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: from xmlrpclib import ServerProxy, Error

In [2]: server = ServerProxy('http://localhost:9002')

In [3]: [m for m in server.system.listMethods() if 'Signal' in m]
Out[3]: ['supervisor.sendGroupSignal', 'supervisor.sendProcessSignal']

In [4]: server.supervisor.sendProcessSignal('dog:4', 1)
Out[4]: True

In [5]: server.supervisor.sendGroupSignal('dog')
Out[5]:
[{'description': 'OK', 'group': 'dog', 'name': '1', 'status': 80},
 {'description': 'OK', 'group': 'dog', 'name': '0', 'status': 80},
 {'description': 'OK', 'group': 'dog', 'name': '3', 'status': 80},
 {'description': 'OK', 'group': 'dog', 'name': '2', 'status': 80},
 {'description': 'OK', 'group': 'dog', 'name': '4', 'status': 80}]

@msabramo
Copy link
Contributor Author

I added frontend (supervisorctl) support in 21ddfff. Looks like this:

❯ supervisorctl
cat:0                            RUNNING   pid 57305, uptime 0:00:07
cat:1                            RUNNING   pid 57304, uptime 0:00:07
cat:2                            RUNNING   pid 57307, uptime 0:00:07
cat:3                            RUNNING   pid 57306, uptime 0:00:07
cat:4                            RUNNING   pid 57308, uptime 0:00:07
dog:0                            RUNNING   pid 57300, uptime 0:00:07
dog:1                            RUNNING   pid 57299, uptime 0:00:07
dog:2                            RUNNING   pid 57302, uptime 0:00:07
dog:3                            RUNNING   pid 57301, uptime 0:00:07
dog:4                            RUNNING   pid 57303, uptime 0:00:07
supervisor> help signal
signal <signal name> <name>           Signal a process
signal <signal name> <gname>:*        Signal all processes in a group
signal <signal name> <name> <name>    Signal multiple processes or groups
supervisor> signal 1 dog:3 dog:4
dog:3: signalled
dog:4: signalled
supervisor> signal HUP dog:3 dog:4
dog:3: signalled
dog:4: signalled
supervisor> signal HUP dog:*
dog:1: signalled
dog:0: signalled
dog:3: signalled
dog:2: signalled
dog:4: signalled
supervisor> signal USR1 dog:1 dog:2
dog:1: signalled
dog:2: signalled

for consistency and PEP8
@sontek
Copy link

sontek commented Aug 14, 2014

I think a restartsignal configuration option should also be introduced. The reasoning for this would be if you run sudo supervisorctl restart all you might want to send a HUP signal where as when you run sudo supervisorctl stop all you probably want to send TERM

@msabramo
Copy link
Contributor Author

from @mcdonc on IRC (#pyramid):

restartsignal i'm +0 on.. i'd never use it myself but it seems to fit peoples' brains
its a little weird because it changes the meaning of "restart", and we dont have prior art for anything
that changes the meaning of a command except for "stopsignal"
i just have a feeling that what people actually want to do is "signal USR2 someprogram"
they'd just rather sort it in their brains as "restart"
i mean i guess its ok
they dont have to use it
it's just for people who need to map things that way in their heads i suppose

@msabramo
Copy link
Contributor Author

We have had folks who wanted quick restarts put stopsignal = HUP in their supervisor config, which is of course, a bad idea, because then supervisor doesn't actually stop things.

@mcdonc
Copy link
Member

mcdonc commented Aug 14, 2014

If the signal people use as "restartsignal" doesnt actually exit the process, they'll be in for a similarly bad time.

@sontek
Copy link

sontek commented Aug 14, 2014

Yeah, I'm totally convinced that restartsignal is not needed.

@mcdonc
Copy link
Member

mcdonc commented Aug 14, 2014

Convincing the thousand folks who think they need it in #53 is probably going to be tricky.

@msabramo
Copy link
Contributor Author

Well, give 'em the signal command and then see what happens.

@mnaberez
Copy link
Member

I remember seeing a fork that had another implementation of this same feature. I couldn't find it with GitHub search, so I cloned all the forks and grepped for signal in their rpcinterface.py files. The only ones I came up with were fedosov (which is for a different issue, restartsignal) and this one. I may have missed it or it may have been deleted.

Edit: Found it, see below.

@@ -464,6 +465,82 @@ def stopAllProcesses(self, wait=True):
killall.rpcinterface = self
return killall # deferred


def _getSignalFromString(self, name):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have this in datatypes.signal_number.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh cool! Fixed in 315b30e.

@mnaberez
Copy link
Member

Found that other implementation:
https://github.com/moriyoshi/supervisor/tree/feature/moriyoshi/add-signal-command

This one should be reviewed as well. One thing I noticed is that it has tests for the new signal command in supervisorctl, which this patch does not. We should at least pull those tests in.

@mcdonc
Copy link
Member

mcdonc commented Aug 18, 2014

  • sendXSignal XMLRPC API methods should probably be named signalX (e.g.
    sendProcessSignal -> signalProcess).
  • As Mike mentioned in his inline notes, I suspect sendGroupSignal doesn't need
    to do anything async. Unlike stopping processes, there's nothing to wait for,
    and sending even a thousand signals wouldn't block the mainloop for any
    considerable time.
  • We might consider adding a signalAllProcesses API, if only for foolish consistency with
    stopAllProcesses.
  • We should probably merge the _stopresult and _signalresult code in
    supervisorctl.
  • I wonder if we need a "signalasgroup" configuration option, like killasgroup. I don't think
    we do, but it does mean that signal HUP someprocess won't be (and can't be made)
    completely equivalent to stop someprocess, which is fine by me, but probably needs
    to be called out in the docs.
  • We should review the supervisorctl tests in
    https://github.com/moriyoshi/supervisor/tree/feature/moriyoshi/add-signal-command
    and adapt them to this implementation.

@mcdonc mcdonc merged commit e34d41c into Supervisor:master Aug 19, 2014
mcdonc added a commit that referenced this pull request Aug 19, 2014
…do anything async in signalGroup, merge logic for _stopresult and _signalresult in supervisorctl
@mcdonc
Copy link
Member

mcdonc commented Aug 19, 2014

Merged to master. I took care of most of the stuff in my comment, delta mining the moriyoshi code for supervisorctl tests.

@adnam
Copy link

adnam commented Nov 12, 2014

My feeling on this is that a "restart" signal should completely stop and then start, just as it does now, so I agree with @sontek that restartsignal is not needed.

I think the supporters of #53 would be happy to have a "graceful" command which can be provided by specifying a "graceful_signal". For gunicorn this would be "HUP" and Apache2 this would be "SIGUSR1". If the command "graceful-restart" is issued for a service for which "gracefulrestartsignal" is not defined, it simply does nothing and issues a warning. Similarly, "graceful-stop" can be provided the same way.

The only remaining problem would be restarting groups of services where the desired behaviour would be:

  • If the service has a graceful signal defined, use it.
  • Otherwise restart "normally" via stop/start

So I would add a "--force" option to the graceful command which falls back to stop/start if no graceful signal is defined.

@IvanAnishchuk
Copy link

it simply does nothing and issues a warning
So I would add a "--force" option to the graceful command which falls back to stop/start if no graceful signal is defined.

I believe that should be the default behavior with option to do nothing if there's no graceful signal defined (--calm?). And warning could be issued while doing the job, I don't think anybody would go and edit the config when they need to restart something and --force option will only increase the command line required for the most needed function (and re-sending rate, sometimes causing unneeded consecutive restart).

@lonetwin
Copy link

Just curious what version of supervisor are these changes set to be released in ? I am looking to just use the signal command and have no preference either ways about also having a 'graceful restart' config option.

@mnaberez
Copy link
Member

The signal command from this pull request will be included in the next release, 3.2.

@jgadling
Copy link

Any ETA on the 3.2 release?

mcdonc added a commit that referenced this pull request Aug 18, 2015
…do anything async in signalGroup, merge logic for _stopresult and _signalresult in supervisorctl
@astlock
Copy link

astlock commented Jan 14, 2016

Thank you for the signal implementation! I found some wrong behaviour with signals and with normal restarts too:

[koshevoy@koshevoy-staging.dal05 ~]$ supervisorctl signal sigusr2 app-api
app-api: ERROR (no such process)
[koshevoy@koshevoy-staging.dal05 ~]$ echo $?
0
[koshevoy@koshevoy-staging.dal05 ~]$ supervisorctl restart elf
elf: ERROR (no such process)
elf: ERROR (no such process)
[koshevoy@koshevoy-staging.dal05 ~]$ echo $?
0

If the restart or signaling failed for any reason, there should be exit code 1. Am I right?

@mnaberez
Copy link
Member

If the restart or signaling failed for any reason, there should be exit code 1. Am I right?

The exit status always being 0 is not limited to signals. It is tracked as #24 and there is now a pull request to change this in #688 that should be merged for a future release.

@astlock
Copy link

astlock commented Jan 14, 2016

I missed this issue. Thank you for the explanation!

@mangelozzi
Copy link

This sounds like a great way to use nginx -s reload to reload the nginx config with zero downtime. Unfortuantely the only help I could find on it says:

signal
No help on signal

Say I have a program called nginx, how would I send the signal to nginx to reload its config?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants