
Show HN: Pact, a simple utility that kills all procs given to it if one dies - nickodell
https://github.com/nickodell/pact
======
hawski
I did something similar some time ago, but in far simpler form. I called it
"process race" \- prace for short.

Basically you write simple shell script to start your processes and at the and
you exec prace so it takes over children of shell:

    
    
      #!/bin/sh
      proc1 &
      proc2 &
      proc3 &
      exec prace
    

You could also do this as a part of shell script in this way:

    
    
      (proc1 & proc2 & proc3 & exec prace)
    

Then prace has simple job. It wait(2)s and then kills all children.

I have it somewhere if someone is interested, but I can access it in few
hours. But everything is written in at most 2/3 terminal screens worth of C.

~~~
gkya
I for one would like to have it at hand, if you could. Just paste it here if
you don't mind publishing it, thanks in advance.

~~~
hawski
For the time being I can't access original implementation, but quick and dirty
version looks like this:
[https://gist.github.com/hadrianw/8e6f9c1007953b37f768](https://gist.github.com/hadrianw/8e6f9c1007953b37f768)

------
gnufied
Props for this. Just last week, I was searching for a similar solution and
ended up coding this - [https://github.com/code-
mancers/invoker/blob/master/lib/invo...](https://github.com/code-
mancers/invoker/blob/master/lib/invoker/power/setup/files/invoker_forwarder.sh.erb)

It doesn't kill the shell, when one of the process dies but kills the
processes if shell dies. There is some trick involved in the way trap gets
called though when shell dies and without waiting on the processes twice -
shell exits without killing child processes.

------
rusanu
If you happen to target Windows platform (I know article does not), don't
reinvent the wheel. There are NT Job Objects [1] for this. The 'target'
process creates the job with `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE` set and
keeps the job handle open. 'dependend' processes (by default all children
spawned by 'target', but you can add more) will all be killed when the
'target' process terminates, no matter how is terminated. Jobs can do more,
like cap CPU/IO/Memory for the job.

[1] [https://msdn.microsoft.com/en-
us/library/windows/desktop/ms6...](https://msdn.microsoft.com/en-
us/library/windows/desktop/ms684161\(v=vs.85\).aspx)

------
nodesocket
Does it make sense to optionally pass the signal you want to send as an
argument?

    
    
        pact --signal SIGINT $PID1 $PID2
        pact -s SIGKILL $PID1 $PID2
        pact $PID1 $PID2 # uses SIGTERM by default

~~~
nickodell
I wrote this to scratch an itch. Is this a feature that would make pact useful
to you? If so, I can add it.

I debated about making it send SIGKILL shortly after sending SIGTERM, but I
was having troubling thinking of an unsurprising way to implement it.

~~~
nodesocket
I can't think of a current itch, but think about sending SIGHUP (refresh
config) instead of killing processes.

------
Terr_
I wonder if you could create a system that gives a file-lock to the last
surviving (child?) process... Call it Tontine.

------
tomc1985
Pact... heh heh... I like the name :)

~~~
Vintila
Sometimes I wonder if people come up with the name first and write something
to match.

------
quakenul
I fucking love the name =)

~~~
x1024
I'm just sitting here - popcorn-in-the-microwave - waiting for _those_ people
to start a fuss about it.

------
azianmike
I might be totally wrong, but isn't this a good way to get orphaned processes?
Kill the parent arbitrarily with SIGTERM (I don't think this automatically
cleans up the children/forked processes) and viola, you've got an orphaned
process.

~~~
sebcat
Using this would require whatever process you start to handle SIGTERM
properly. Most processes spawning children do this, but it's no guarantee and
one needs to be aware of this.

In my experience, processes doing IPC with parent gets notified of parental
death by EOF on the socketpair/pipe it's using to communicate with the parent.
This is easy to reason about and most people check return values from I/O
functions. Parents spawning children and only caring about SIGCHLD are more
prone to not have the correct signal handlers set up by its dev(s).

IMO, any process spawning children w/o proper signal handlers are not good
citizens.

------
sandGorgon
This is great, and if you can - you should probably submit it as a request to
systemd and supervisor.

I can see how I would use it in supervisord within a group.

------
JoachimSchipper
This is a neat hack, but pids are reused - there is a reason "proper"
supervisors take care to be the parent of the supervised process.

(A process monitoring system will mostly trigger under odd conditions... such
as fork bombs.)

~~~
nickodell
You're right, but I think it's an acceptable risk.

pact wakes up every second to check that every process is still there. If the
process is gone, it sets the procChanged field in the struct, and it won't
kill it later.

~~~
int0x80
Still, what you are doing is inherently racy. The very moment you pass the
PIDs to your program, they can already be gone and reused. You can end up
kill()ing a different PID. I don't think you can use this for anything
serious. In what situation do you think it might be acceptable? EDIT: You are
trying to implement process groups in user space.

------
kazinator
I'd call this "atomic bomb".

If allusions to suicide pacts are fair game, so is mass killing; and atomic
means "all or nothing" in CS.

~~~
zappo2938
Over at MongoDB, Inc. atomic means nothing at all.

~~~
jeswin
MongoDB is quite decent these days. Their WiredTiger backbend is written by
the Berkeley DB guys.

------
polm23
Maybe this is a silly question, but what's a situation where you would want to
use this?

------
ufo
I wonder what happens if you give it its own process ID.

------
blantonl
I don't get it.. The name that is.

~~~
RunawayGalaxy
I assume it's Pact as in "death pact".

------
otoburb
The combination of the ghoulish name and correspondingly succinct description
brings to mind the style of a Magic: The Gathering card.

~~~
bobbles
And such a card exists!

[http://gatherer.wizards.com/Pages/Card/Details.aspx?multiver...](http://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=247142)

~~~
loarabia
Because of this post and these comments I'm now wondering if M:tG is Turing
complete. <heads off to google>

~~~
PeCaN
Spoiler: yes.

I wonder if there's anything in the rules to deal with the fact that a game
might never complete.

~~~
raker
If there is a truly unstoppable loop (considering usage of the word "may" or
such optional ability to continue or break a loop) then the game is considered
a tie. There are tournament rules regarding players intentionally drawing out
the game (it's against the rules), but I don't think there's any rule against
a deck that simply runs long (or really long).

~~~
thaumasiotes
Some cards have been banned for causing tournament rounds to run too long, or
for being central in decks that regularly do this (I believe Sensei's Divining
Top and the "eggs" deck were the major offenders).

------
MonadQueen
This is like the Erlang / OTP "One for All" strategy.

[http://www.erlang.org/doc/design_principles/sup_princ.html](http://www.erlang.org/doc/design_principles/sup_princ.html)

~~~
rdtsc
I was actually thinking of process linking. Any groups of processes can be
linked. Processes that are linked together -- die together.

