Is it possible to force a Ruby program to run as a proc name different than "ruby"?

  • Follow


Hi, I have a Python software called "py_program". It runs as daemon in Linu=
x=20
so doing a "ps" I get:

  root 6541 /usr/bin/python /home/ibc/py_program

However in /proc/6541/status I read:

  Name:   py_program

This is good because this means that in Debian it can be stopped with the=20
command:

  start-stop-daemon --stop --name py_program

Anyhow the proces name is "python" still rather than "py_program":

  ~# netstat -putan | grep 6541
  6541/python

and I cannot kill the process with "killall py_program".


Well, I'm coding a server "rb_program" in Ruby (a HTTP server built with Ra=
ck)=20
and the behavior is different:

  root 5412 ruby1.9 /home/ibc/rb_program

In /proc/5412/status:

  Name:     ruby1.9

So I cannot use "start-stop-daemon --stop --name rb_program" because it wou=
ld=20
find no process names "rb_program"
(and of course I cannot use "--name ruby1.9" as I would stop any ruby progr=
am=20
running in the host).


So, is there some way to force the process to appear as "rb_program" in=20
/proc/PID/status?

Thanks a lot.

 =20


=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply ibc (607) 12/11/2009 10:34:04 PM

El Viernes, 11 de Diciembre de 2009, I=C3=B1aki Baz Castillo escribi=C3=B3:
> So, is there some way to force the process to appear as "rb_program" in=20
> /proc/PID/status?

I forgot to say that a dirty workaround is creating a link to ruby binary =
=20
called "rb_program".

Of course is really dirty :)


=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/11/2009 11:08:02 PM


On Friday 11 December 2009 04:34:04 pm I=C3=B1aki Baz Castillo wrote:
> This is good because this means that in Debian it can be stopped with the
> command:
>=20
>   start-stop-daemon --stop --name py_program
[snip]
> So I cannot use "start-stop-daemon --stop --name rb_program" because it
>  would find no process names "rb_program"

This is probably not a good idea in the first place -- it means you can't h=
ave=20
separate copies of the program running, and start/stop them independently, =
to=20
say nothing of the possibility that some other program might share the same=
=20
name.

Since you're using start-stop-daemon anyway, why don't you make a pidfile?

start-stop-daemon --start --startas /home/ibc/rb_program --make-pidfile --
pidfile /var/run/rb_program.pid --background

If your program is backgrounding itself already, configure it to create its=
=20
own pidfile -- shouldn't be too hard. Then you can do this instead:

start-stop-daemon --stop --pidfile /var/run/rb_program.pid

> So, is there some way to force the process to appear as "rb_program" in
> /proc/PID/status?

I'd like to know that, too, because it'd be useful for things like killall=
=20
when things get out of hand. But even if there was, this is still the wrong=
=20
approach -- your start-stop-daemon command is sort of equivalent to killall=
,=20
which is a really blunt instrument.

0
Reply David 12/11/2009 11:11:06 PM

El S=C3=A1bado, 12 de Diciembre de 2009, David Masover escribi=C3=B3:

> > So I cannot use "start-stop-daemon --stop --name rb_program" because it
> >  would find no process names "rb_program"
>=20
> This is probably not a good idea in the first place -- it means you can't
>  have separate copies of the program running, and start/stop them
>  independently, to say nothing of the possibility that some other program
>  might share the same name.
>=20
> Since you're using start-stop-daemon anyway, why don't you make a pidfile?
>=20
> start-stop-daemon --start --startas /home/ibc/rb_program --make-pidfile --
> pidfile /var/run/rb_program.pid --background
>=20
> If your program is backgrounding itself already, configure it to create i=
ts
> own pidfile -- shouldn't be too hard. Then you can do this instead:
>=20
> start-stop-daemon --stop --pidfile /var/run/rb_program.pid

Yes, in fact I use it now: my Ruby server creates a pidfile.

The good point of using:

  start-stop-daemon --stop --pidfile /var/run/rb_program.pid --name rb_prog=
ram

is that it would stop the process just if it's called "rb_program" and its =
pid=20
matches the value of /var/run/rb_program.pid, so you cannot kill any other=
=20
process using that pid by accident (it could occur if your program didn't=20
delete the pidfile and a new process has taken same pid value).


> > So, is there some way to force the process to appear as "rb_program" in
> > /proc/PID/status?
>=20
> I'd like to know that, too, because it'd be useful for things like killall
> when things get out of hand. But even if there was, this is still the wro=
ng
> approach -- your start-stop-daemon command is sort of equivalent to
>  killall, which is a really blunt instrument.
>=20


=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/11/2009 11:33:06 PM

On Friday 11 December 2009 05:33:06 pm I=C3=B1aki Baz Castillo wrote:
> The good point of using:
>=20
>   start-stop-daemon --stop --pidfile /var/run/rb_program.pid --name
>  rb_program
>=20
> is that it would stop the process just if it's called "rb_program" and its
>  pid matches the value of /var/run/rb_program.pid, so you cannot kill any
>  other process using that pid by accident (it could occur if your program
>  didn't delete the pidfile and a new process has taken same pid value).

That's a good point -- though I would guess that in theory, it shouldn't be=
=20
possible for a program to die in such a way that it wouldn't be able to del=
ete=20
that file. The only thing that would make sense is a reboot, and on my syst=
em,=20
/var/run is a tmpfs (only exists in RAM/swap), so it's not stored anywhere=
=20
that would survive a reboot.

I can think of a few other possibilities, like checking directly (with fuse=
r,=20
for example) which process is controlling the resource your daemon is=20
associated with, or even talking to the old daemon over a socket, or some s=
ort=20
of formal IPC like dbus.

I'm not sure about Debian, but on Ubuntu, the upstart system might also be=
=20
worth looking into.

I did find a solution, though:

#!/usr/bin/env ruby

doesn't work. However:

#!/usr/bin/ruby1.9.1

produces a process which responds both to killall and to 'start-stop-daemon=
 --
stop --name'. But hardcoding the location of the Ruby interpreter is=20
antisocial, especially when there are so many of them. The whole point of e=
nv=20
is that I can always override PATH and point to a different Ruby interprete=
r,=20
to easily switch between 1.8, 1.9, JRuby, Rubinius, etc.

I thought I'd found a workaround, and I've been getting messy with C trying=
 to=20
figure out how to replace env with a more appropriate program, but I'm not=
=20
sure how to change the program name at all. That is, this isn't a Ruby issu=
e,=20
it's a Linux/Unix issue. The best I could figure out was this:


#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[]) {
  if (argc =3D=3D 1) {
    fprintf(stderr, "Usage: %s PROGRAM ARGUMENTS\n", argv[0]);
    return 1;
  }

  char * filename =3D argv[1];
  argv[1] =3D "foo";

    execvp(filename, argv+1);

  char * outstr =3D malloc(strlen(argv[0]) + strlen(argv[1]) + 2);
  sprintf(outstr, "%s: %s", argv[0], argv[1]);
  perror(outstr);
  return errno;
}


Compile that, then change the Ruby script to be:

#!/path/to/that/binary ruby

The same should work for Python.

Except it doesn't.

It does indeed change the program name in /proc/self/cmdline -- it becomes=
=20
'foo /name/of/my/program.rb'. And killall and start-stop-daemon both seem t=
o=20
work, here, but only when I give them "ruby" as the name of the program to=
=20
kill.

Notice, also, I'm explicitly setting 'foo' as the program name. If this=20
worked, I'd detect that dynamically -- but it doesn't.

At this point, I'm about ready to write a script that would copy your scrip=
t=20
(or create a wrapper for your script) and change the shebang to match `whic=
h=20
ruby` at the point of invocation, but that wouldn't work either -- that wil=
l=20
fool the program name in /proc, but it won't fool your program -- there's $=
0=20
and probably a dozen other things I haven't thought of to tell it that it's=
=20
being loaded by a separate script.

I don't really know what else to try. /proc/self/exe is no help; that point=
s=20
to the Ruby binary no matter what. You might write your own script that gre=
ps=20
through /proc/*/cmdline, but I don't see a way to fool start-stop-daemon=20
without changing to #!/usr/bin/ruby1.9.1.

0
Reply David 12/12/2009 1:21:10 AM

El S=C3=A1bado, 12 de Diciembre de 2009, David Masover escribi=C3=B3:
> On Friday 11 December 2009 05:33:06 pm I=C3=B1aki Baz Castillo wrote:
> > The good point of using:
> >
> >   start-stop-daemon --stop --pidfile /var/run/rb_program.pid --name
> >  rb_program
> >
> > is that it would stop the process just if it's called "rb_program" and
> > its pid matches the value of /var/run/rb_program.pid, so you cannot kill
> > any other process using that pid by accident (it could occur if your
> > program didn't delete the pidfile and a new process has taken same pid
> > value).
>=20
> That's a good point -- though I would guess that in theory, it shouldn't =
be
> possible for a program to die in such a way that it wouldn't be able to
>  delete that file. The only thing that would make sense is a reboot, and =
on
>  my system, /var/run is a tmpfs (only exists in RAM/swap), so it's not
>  stored anywhere that would survive a reboot.

Well, usually daemons are coded to deelte the pidfile upon receipt of a SIG=
INT=20
signal (or some others). But if the daemon is killed with "kill -9 PID" the=
n=20
it terminates inmediately without deleting the piddile.

In the case of a crash or segmentfault the daemon wouldn't delete the pidfi=
le=20
again.

I've coded my Debian init script "start" action so it deletes the existing=
=20
"pidfile" if it exists (it shouldn't).


> I can think of a few other possibilities, like checking directly (with
>  fuser, for example) which process is controlling the resource your daemon
>  is associated with, or even talking to the old daemon over a socket, or
>  some sort of formal IPC like dbus.

Sounds interesting, but perhaps a bit complex. I think I don't need so much=
 as=20
there will be an unique instance of the ruby program running in the server.



> I did find a solution, though:
>=20
> #!/usr/bin/env ruby
>=20
> doesn't work. However:
>=20
> #!/usr/bin/ruby1.9.1
>=20
> produces a process which responds both to killall and to 'start-stop-daem=
on
>  -- stop --name'.

Great! this is the point. I've checked the daemon in python and it uses=20
"/usr/bin/python" rather than "/usr/bin/env python".


>  But hardcoding the location of the Ruby interpreter is
>  antisocial, especially when there are so many of them. The whole point of
>  env is that I can always override PATH and point to a different Ruby
>  interpreter, to easily switch between 1.8, 1.9, JRuby, Rubinius, etc.

Yes, and when dealing with compiled sources rather than linux distribution=
=20
specific packages we could have ruby1.9 binay in /usr/local/bin/, /opt/bin/=
=2E..
I agree 100%. I wouldn't like to hardcode the ruby location.
=09
=20
> I thought I'd found a workaround, and I've been getting messy with C tryi=
ng
>  to figure out how to replace env with a more appropriate program, but I'm
>  not sure how to change the program name at all. That is, this isn't a Ru=
by
>  issue, it's a Linux/Unix issue. The best I could figure out was this:
>=20
>=20
> #include <unistd.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <errno.h>
>=20
> int main(int argc, char *argv[]) {
>   if (argc =3D=3D 1) {
>     fprintf(stderr, "Usage: %s PROGRAM ARGUMENTS\n", argv[0]);
>     return 1;
>   }
>=20
>   char * filename =3D argv[1];
>   argv[1] =3D "foo";
>=20
>     execvp(filename, argv+1);
>=20
>   char * outstr =3D malloc(strlen(argv[0]) + strlen(argv[1]) + 2);
>   sprintf(outstr, "%s: %s", argv[0], argv[1]);
>   perror(outstr);
>   return errno;
> }
>=20
>=20
> Compile that, then change the Ruby script to be:
>=20
> #!/path/to/that/binary ruby
>=20
> The same should work for Python.
>=20
> Except it doesn't.
>=20
> It does indeed change the program name in /proc/self/cmdline -- it becomes
> 'foo /name/of/my/program.rb'. And killall and start-stop-daemon both seem
>  to work, here, but only when I give them "ruby" as the name of the progr=
am
>  to kill.
>=20
> Notice, also, I'm explicitly setting 'foo' as the program name. If this
> worked, I'd detect that dynamically -- but it doesn't.
>=20
> At this point, I'm about ready to write a script that would copy your
>  script (or create a wrapper for your script) and change the shebang to
>  match `which ruby` at the point of invocation, but that wouldn't work
>  either -- that will fool the program name in /proc, but it won't fool yo=
ur
>  program -- there's $0 and probably a dozen other things I haven't thought
>  of to tell it that it's being loaded by a separate script.
>=20
> I don't really know what else to try. /proc/self/exe is no help; that
>  points to the Ruby binary no matter what. You might write your own script
>  that greps through /proc/*/cmdline, but I don't see a way to fool
>  start-stop-daemon without changing to #!/usr/bin/ruby1.9.1.

Thanks a lot for all your suggestions, it's a really interesting subject.
However I would prefer to keep the code as simple as possible. The only I=20
wanted was the possibility of kill my program using "killall rb_program".

To summarize this is possible in these cases:

a) Hardcoding the ruby location (avoiding using "env").
Not user-friendly.

b) Creating a link "rb_program" to ruby interpreter and invoke my program w=
ith=20
"rb_program /PATH_TO_rb_program.rb".
Not very beauty :)

c) Replacing env with your above suggestion.
It involves compiling a C program, it could break something in a not pure=20
Linux environment...

Well, I've learnt *a lot* in this thread but at this point I think is bette=
r=20
just to leave the code as it is.
Really thanks a lot.


=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/12/2009 9:53:06 AM

Iñaki Baz Castillo wrote:
> So, is there some way to force the process to appear as "rb_program" in
> /proc/PID/status?

Have you tried

  $0 = 'rb_program'

?

You may find there's a problem if your program name is longer than some 
hard-coded limit. There is a workaround at 
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/336743

At the top of your program put:

$progname = $0
alias $PROGRAM_NAME $0
alias $0 $progname
trace_var(:$0) {|val| $PROGRAM_NAME = val} # update for ps
-- 
Posted via http://www.ruby-forum.com/.

0
Reply Brian 12/12/2009 12:58:02 PM

Brian Candler wrote:
> Iñaki Baz Castillo wrote:
>> So, is there some way to force the process to appear as "rb_program" in
>> /proc/PID/status?
> 
> Have you tried
> 
>   $0 = 'rb_program'
> 
> ?

... or I can't remember the details, but perhaps you needed 
$0.replace('rb_program'), but that doesn't work for newer versions of 
Ruby where $0 is a frozen string, hence the required special code:

> $progname = $0
> alias $PROGRAM_NAME $0
> alias $0 $progname
> trace_var(:$0) {|val| $PROGRAM_NAME = val} # update for ps

-- 
Posted via http://www.ruby-forum.com/.

0
Reply Brian 12/12/2009 12:59:25 PM

El S=C3=A1bado, 12 de Diciembre de 2009, Brian Candler escribi=C3=B3:
> Brian Candler wrote:
> > I=C3=B1aki Baz Castillo wrote:
> >> So, is there some way to force the process to appear as "rb_program" in
> >> /proc/PID/status?
> >
> > Have you tried
> >
> >   $0 =3D 'rb_program'
> >
> > ?
>=20
> ... or I can't remember the details, but perhaps you needed
> $0.replace('rb_program'), but that doesn't work for newer versions of
>=20
> Ruby where $0 is a frozen string, hence the required special code:
> > $progname =3D $0
> > alias $PROGRAM_NAME $0
> > alias $0 $progname
> > trace_var(:$0) {|val| $PROGRAM_NAME =3D val} # update for ps

Thanks a lot, it sounds really interesting.

However all the above works for me just by adding at the top:
   $0 =3D "rb_program"
or:
  $PROGRAM_NAME =3D "rb_program"=20

With it when I do a "ps" I see "rb_program" which is great.

However in /proc/PID/status I still have the same described issues: "Name:=
=20
ruby1.9", so I cannot do "killall rb_program".

This can be solved by using:
  #!/usr/local/bin/ruby1.9
rather than:
  #!/usr/bin/env ruby1.9

but of course hardcoding the location of ruby is not very good approach=20
(specially when you want your code to run on any Linux system).

Thanks a lot.




=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/12/2009 1:49:46 PM

El S=C3=A1bado, 12 de Diciembre de 2009, I=C3=B1aki Baz Castillo escribi=C3=
=B3:


> However in /proc/PID/status I still have the same described issues: "Name:
> ruby1.9", so I cannot do "killall rb_program".

It seems to be more a "killall" issue since "pidof rb_program" works while=
=20
"killall rb_program" not.

=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/12/2009 1:53:13 PM

El S=C3=A1bado, 12 de Diciembre de 2009, I=C3=B1aki Baz Castillo escribi=C3=
=B3:
> El S=C3=A1bado, 12 de Diciembre de 2009, I=C3=B1aki Baz Castillo escribi=
=C3=B3:
> > However in /proc/PID/status I still have the same described issues:
> > "Name: ruby1.9", so I cannot do "killall rb_program".
>=20
> It seems to be more a "killall" issue since "pidof rb_program" works while
> "killall rb_program" not.
>=20

I read in http://psmisc.sourceforge.net/changelog.html:

=2D---------
Changes from version 12 to 13 (16-APR-1997)

killall: now lists PIDs if invoked as "pidof" (proposed by Peter Daum)=20
=2D--------

This, if I do "killall rb_" and pres TAB (I've autocompletion) I get "killa=
ll=20
rb_program" but it doesn't work, it doesn't kill the process.
However if I do "pidof rb_program" I get its pid.

Strange... I'll report a bug in psmisc.

=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/12/2009 2:19:00 PM

On 12.12.2009 10:53, I=F1aki Baz Castillo wrote:
> El S=E1bado, 12 de Diciembre de 2009, David Masover escribi=F3:
>> On Friday 11 December 2009 05:33:06 pm I=F1aki Baz Castillo wrote:
>>> The good point of using:
>>>
>>>   start-stop-daemon --stop --pidfile /var/run/rb_program.pid --name
>>>  rb_program
>>>
>>> is that it would stop the process just if it's called "rb_program" an=
d
>>> its pid matches the value of /var/run/rb_program.pid, so you cannot k=
ill
>>> any other process using that pid by accident (it could occur if your
>>> program didn't delete the pidfile and a new process has taken same pi=
d
>>> value).
>> That's a good point -- though I would guess that in theory, it shouldn=
't be
>> possible for a program to die in such a way that it wouldn't be able t=
o
>>  delete that file. The only thing that would make sense is a reboot, a=
nd on
>>  my system, /var/run is a tmpfs (only exists in RAM/swap), so it's not=

>>  stored anywhere that would survive a reboot.
>=20
> Well, usually daemons are coded to deelte the pidfile upon receipt of a=
 SIGINT=20
> signal (or some others). But if the daemon is killed with "kill -9 PID"=
 then=20
> it terminates inmediately without deleting the piddile.
>=20
> In the case of a crash or segmentfault the daemon wouldn't delete the p=
idfile=20
> again.
>=20
> I've coded my Debian init script "start" action so it deletes the exist=
ing=20
> "pidfile" if it exists (it shouldn't).

You can make deletion conditionally depending on the presence of the=20
process (kill 0).  This is what I would do:

VAR=3D'/var/run'

pid_file =3D File.join(VAR, File.basename($0) + '.pid')

begin
   old_pid =3D File.read(pid_file).to_i
   Process.kill 0, old_pid
   $stderr.puts "ERROR: already running with PID #{old_pid}"
   exit 1
rescue Errno::ENOENT
   # no pid file
rescue Errno::ESRCH
   # process not running
   $stderr.puts 'WARNING: stale pid file'
end

# open file with EXCL in order to catch race conditions where two
# processes were started almost at the same time and both thought
# they would be a new instance.  Uncomment sleep to simulate:
# sleep 2
File.open(pid_file, File::EXCL | File::WRONLY | File::CREAT) {|io|=20
io.write($$)}
trap(0) {File.delete pid_file}

puts "OK, here we go."

# just for testing purposes:
File.read(pid_file).to_i =3D=3D $$ or raise "What went wrong?"

sleep 10

puts "Finished"


> Thanks a lot for all your suggestions, it's a really interesting subjec=
t.
> However I would prefer to keep the code as simple as possible. The only=
 I=20
> wanted was the possibility of kill my program using "killall rb_program=
".

Why does it have to be "killall"?  What about providing a command line=20
option "-k" or "--kill" for killing (e.g. as ssh-agent does)?  You could =

integrate that pretty easily with the PID handling code above.

> To summarize this is possible in these cases:
>=20
> a) Hardcoding the ruby location (avoiding using "env").
> Not user-friendly.

I personally do not find it too unfriendly to place the interpreter name =

with an absolute path in the script.  This has also greater safety and=20
robustness: the one installing the program and ruby interpreter (some=20
person with administrative permissions) is likely the same and can=20
ensure location is set properly.  Relying on users' environments is more =

fragile IMHO.

> b) Creating a link "rb_program" to ruby interpreter and invoke my progr=
am with=20
> "rb_program /PATH_TO_rb_program.rb".
> Not very beauty :)
>=20
> c) Replacing env with your above suggestion.
> It involves compiling a C program, it could break something in a not pu=
re=20
> Linux environment...
>=20
> Well, I've learnt *a lot* in this thread but at this point I think is b=
etter=20
> just to leave the code as it is.
> Really thanks a lot.

Well, it's your choice.

Kind regards

	robert


--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
0
Reply Robert 12/12/2009 4:24:00 PM

El S=E1bado, 12 de Diciembre de 2009, Robert Klemme escribi=F3:
> On 12.12.2009 10:53, I=F1aki Baz Castillo wrote:
> > El S=E1bado, 12 de Diciembre de 2009, David Masover escribi=F3:
> >> On Friday 11 December 2009 05:33:06 pm I=F1aki Baz Castillo wrote:
> >>> The good point of using:
> >>>
> >>>   start-stop-daemon --stop --pidfile /var/run/rb_program.pid --name
> >>>  rb_program
> >>>
> >>> is that it would stop the process just if it's called "rb_program" and
> >>> its pid matches the value of /var/run/rb_program.pid, so you cannot
> >>> kill any other process using that pid by accident (it could occur if
> >>> your program didn't delete the pidfile and a new process has taken sa=
me
> >>> pid value).
> >>
> >> That's a good point -- though I would guess that in theory, it shouldn=
't
> >> be possible for a program to die in such a way that it wouldn't be able
> >> to delete that file. The only thing that would make sense is a reboot,
> >> and on my system, /var/run is a tmpfs (only exists in RAM/swap), so it=
's
> >> not stored anywhere that would survive a reboot.
> >
> > Well, usually daemons are coded to deelte the pidfile upon receipt of a
> > SIGINT signal (or some others). But if the daemon is killed with "kill =
=2D9
> > PID" then it terminates inmediately without deleting the piddile.
> >
> > In the case of a crash or segmentfault the daemon wouldn't delete the
> > pidfile again.
> >
> > I've coded my Debian init script "start" action so it deletes the
> > existing "pidfile" if it exists (it shouldn't).
>=20
> You can make deletion conditionally depending on the presence of the
> process (kill 0).  This is what I would do:
>=20
> VAR=3D'/var/run'
>=20
> pid_file =3D File.join(VAR, File.basename($0) + '.pid')
>=20
> begin
>    old_pid =3D File.read(pid_file).to_i
>    Process.kill 0, old_pid
>    $stderr.puts "ERROR: already running with PID #{old_pid}"
>    exit 1
> rescue Errno::ENOENT
>    # no pid file
> rescue Errno::ESRCH
>    # process not running
>    $stderr.puts 'WARNING: stale pid file'
> end
>=20
> # open file with EXCL in order to catch race conditions where two
> # processes were started almost at the same time and both thought
> # they would be a new instance.  Uncomment sleep to simulate:
> # sleep 2
> File.open(pid_file, File::EXCL | File::WRONLY | File::CREAT) {|io|
> io.write($$)}
> trap(0) {File.delete pid_file}
>=20
> puts "OK, here we go."
>=20
> # just for testing purposes:
> File.read(pid_file).to_i =3D=3D $$ or raise "What went wrong?"
>=20
> sleep 10
>=20
> puts "Finished"
>=20
> > Thanks a lot for all your suggestions, it's a really interesting subjec=
t.
> > However I would prefer to keep the code as simple as possible. The only=
 I
> > wanted was the possibility of kill my program using "killall rb_program=
".
>=20
> Why does it have to be "killall"?  What about providing a command line
> option "-k" or "--kill" for killing (e.g. as ssh-agent does)?  You could
> integrate that pretty easily with the PID handling code above.
>=20
> > To summarize this is possible in these cases:
> >
> > a) Hardcoding the ruby location (avoiding using "env").
> > Not user-friendly.
>=20
> I personally do not find it too unfriendly to place the interpreter name
> with an absolute path in the script.  This has also greater safety and
> robustness: the one installing the program and ruby interpreter (some
> person with administrative permissions) is likely the same and can
> ensure location is set properly.  Relying on users' environments is more
> fragile IMHO.
>=20
> > b) Creating a link "rb_program" to ruby interpreter and invoke my progr=
am
> > with "rb_program /PATH_TO_rb_program.rb".
> > Not very beauty :)
> >
> > c) Replacing env with your above suggestion.
> > It involves compiling a C program, it could break something in a not pu=
re
> > Linux environment...
> >
> > Well, I've learnt *a lot* in this thread but at this point I think is
> > better just to leave the code as it is.
> > Really thanks a lot.
>=20
> Well, it's your choice.


Thanks a lot!


=2D-=20
I=F1aki Baz Castillo <ibc@aliax.net>

0
Reply iso 12/12/2009 6:09:38 PM

On Saturday 12 December 2009 03:53:06 am I=C3=B1aki Baz Castillo wrote:

> Well, usually daemons are coded to deelte the pidfile upon receipt of a
>  SIGINT signal (or some others). But if the daemon is killed with "kill -9
>  PID" then it terminates inmediately without deleting the piddile.

True. I tried (and failed) to find an example of this working. However, a=20
separate process can watch your process and clean up after it however it di=
es.=20
I think this is the principle behind letting init handle it -- take "upstar=
t".

> In the case of a crash or segmentfault the daemon wouldn't delete the
>  pidfile again.

If the crash raises an exception, you can catch that. Segmentation faults=20
trigger SIGSEGV, which you can trap. I suspect you'd have a chance to at le=
ast=20
fire that unlink call with any death except a 'kill -9'.

> > I can think of a few other possibilities, like checking directly (with
> >  fuser, for example) which process is controlling the resource your
> > daemon is associated with, or even talking to the old daemon over a
> > socket, or some sort of formal IPC like dbus.
>=20
> Sounds interesting, but perhaps a bit complex. I think I don't need so mu=
ch
>  as there will be an unique instance of the ruby program running in the
>  server.

Yes, probably too complex to do for a specific program. However, it might b=
e=20
worth wrapping into a library, if there isn't already one designed for this.

> Thanks a lot for all your suggestions, it's a really interesting subject.
> However I would prefer to keep the code as simple as possible. The only I
> wanted was the possibility of kill my program using "killall rb_program".
>=20
> To summarize this is possible in these cases:
>=20
> a) Hardcoding the ruby location (avoiding using "env").
> Not user-friendly.

However, if you distribute your app as a gem, this problem actually goes aw=
ay.=20
Here's the top of gems/rake-0.8.7/bin/rake:

#!/usr/bin/env ruby

#--
# Copyright (c) 2003, 2004, 2005, 2006, 2007  Jim Weirich
=2E..

Here's what it actually installs into your PATH:

#!/usr/bin/ruby1.9.1
#
# This file was generated by RubyGems.
#
# The application 'rake' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require 'rubygems'

version =3D ">=3D 0"

if ARGV.first =3D~ /^_(.*)_$/ and Gem::Version.correct? $1 then
  version =3D $1
  ARGV.shift
end

gem 'rake', version
load Gem.bin_path('rake', 'rake', version)



So, that gives you the best of both worlds -- it's actually somewhat like o=
ne=20
of the crazier solutions I suggested.

> b) Creating a link "rb_program" to ruby interpreter and invoke my program
>  with "rb_program /PATH_TO_rb_program.rb".
> Not very beauty :)
>=20
> c) Replacing env with your above suggestion.

Except (c) doesn't work. I thought it would work, and I posted it to the li=
st=20
in case I was close enough for someone to pick up where I left off.

> It involves compiling a C program, it could break something in a not pure
> Linux environment...

Well, the idea was that if this worked, it'd be generally useful. After all=
,=20
env is on every system, and many Ruby scripts rely on that. So again, not=20
something specific to your program.

0
Reply David 12/12/2009 7:43:32 PM

El S=C3=A1bado, 12 de Diciembre de 2009, David Masover escribi=C3=B3:
> On Saturday 12 December 2009 03:53:06 am I=C3=B1aki Baz Castillo wrote:
> > Well, usually daemons are coded to deelte the pidfile upon receipt of a
> >  SIGINT signal (or some others). But if the daemon is killed with "kill
> > -9 PID" then it terminates inmediately without deleting the piddile.
>=20
> True. I tried (and failed) to find an example of this working. However, a
> separate process can watch your process and clean up after it however it
>  dies. I think this is the principle behind letting init handle it -- take
>  "upstart".

I should take a deep look to "upstart". Until now I'm just used to usual Li=
nux=20
init scripts. But since Debian will adopt upstart it's good time to learn i=
t=20
:)


> > In the case of a crash or segmentfault the daemon wouldn't delete the
> >  pidfile again.
>=20
> If the crash raises an exception, you can catch that.

Yes, I catch all the exceptions, I meant segfaults that can occur when usin=
g=20
Ruby C extensions (or when a Ruby bug occurs).


> Segmentation faults
> trigger SIGSEGV, which you can trap.

Ops, I didn't know it at all. Really interesting.


> I suspect you'd have a chance to at
>  least fire that unlink call with any death except a 'kill -9'.

Ok, so do you say that using "upstart" this problem could be solved as upst=
art=20
itself could manage it when detects a service crash?


> > To summarize this is possible in these cases:
> >
> > a) Hardcoding the ruby location (avoiding using "env").
> > Not user-friendly.
>=20
> However, if you distribute your app as a gem, this problem actually goes
>  away. Here's the top of gems/rake-0.8.7/bin/rake:
>=20
> #!/usr/bin/env ruby
>=20
> #--
> # Copyright (c) 2003, 2004, 2005, 2006, 2007  Jim Weirich
> ...
>=20
> Here's what it actually installs into your PATH:
>=20
> #!/usr/bin/ruby1.9.1
> #
> # This file was generated by RubyGems.

> So, that gives you the best of both worlds -- it's actually somewhat like
>  one of the crazier solutions I suggested.

Great. However I'm not sure if my program would fit well as a gem. It's not=
 a=20
library or utility but a whole http server (for XCAP protocol). This is, it=
=20
will have conf files into /etc directory and so. I've never seen a gem that=
=20
installs a server by itself and contains files in /etc.

Also, I need a Debian init/upstart script so a gem is not fully valid for m=
e.

=20

Thanks a lot for your help.


=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/12/2009 9:54:00 PM

On Saturday 12 December 2009 03:54:00 pm I=C3=B1aki Baz Castillo wrote:
> El S=C3=A1bado, 12 de Diciembre de 2009, David Masover escribi=C3=B3:
> > I suspect you'd have a chance to at
> >  least fire that unlink call with any death except a 'kill -9'.
>=20
> Ok, so do you say that using "upstart" this problem could be solved as
>  upstart itself could manage it when detects a service crash?

I'm saying most aspects of it can be solved within the program -- anything=
=20
except 'kill -9'. With something like upstart, even that should be solvable=
=2E=20
On OS X, I think launchd is similar. Basically, you have one (or more) cent=
ral=20
process(es) which manage the launching and killing of daemons.

At this point, you don't even have to use pidfiles, you can just use=20
variables. In pseudocode:

class Process
  def start
    unless running?
      if @pid =3D fork
        waitpid(@pid) do
          @pid =3D nil
        end
      else
        exec @cmdline
      end
    end
  end
  def stop
    kill @pid
  end
end

The main reason that's pseudocode is that upstart very likely already does=
=20
this for you (so why reinvent the wheel in Ruby?), and because waitpid does=
n't=20
actually work that way.

But basically, the only problem with this model is that if the process=20
responsible for watching your process dies abnormally, either the pidfile=20
won't be cleaned up (if there is one), or you'll now have an unmonitored co=
py=20
of your process running (so you'll need something like killall again). If=20
you're using something like upstart, that's not really a problem -- remembe=
r,=20
upstart is init, which means the second it dies, the kernel panics. In othe=
r=20
words, it doesn't die.

> > So, that gives you the best of both worlds -- it's actually somewhat li=
ke
> >  one of the crazier solutions I suggested.
>=20
> Great. However I'm not sure if my program would fit well as a gem. It's n=
ot
>  a library or utility but a whole http server (for XCAP protocol). This i=
s,
>  it will have conf files into /etc directory and so. I've never seen a gem
>  that installs a server by itself and contains files in /etc.

The usual approach I'd suggest here is, store a configfile path, something=
=20
like the PATH variable, in which later configfiles override values set by=20
earlier ones. Then, set all the default values in a sample config file insi=
de=20
your gem, and let the admin put a conf file in /etc/rb_app (or in ~/.rb_app=
,=20
or in a place specified by the environment variable RB_APP_CONFIG, or in a=
=20
place specified by --config on the commandline) if they want to override=20
something.

That just leaves this part:

> Also, I need a Debian init/upstart script so a gem is not fully valid for
>  me.

That much is possibly true -- you'd need a script that installs/updates tha=
t=20
script.

If you're worried about people going so far as to have separate Ruby=20
interpreters, I'd suggest letting them write their own script, and simply=20
provide documentation, and maybe a command to install some default samples.=
=20
Those scripts would likely be very simple anyway.

On the other hand, you might consider just building a Debian package,=20
depending on the interpreter you want, and hardcoding it into the shebang a=
nd=20
the upstart scripts. Let people download the source if they want to tweak i=
t=20
further. But I'd only go this route if you're content to depend on the Ruby=
=20
libraries that are already packaged in Debian -- unlike some other package=
=20
managers, apt lacks a way to depend directly on truly alien packages.=20
(Contrast to Gobo, in which system packages can depend directly on gems, CP=
AN=20
modules, etc -- I know Gentoo could depend on CPAN modules, too.)

0
Reply David 12/12/2009 10:29:50 PM

El S=C3=A1bado, 12 de Diciembre de 2009, David Masover escribi=C3=B3:
> On Saturday 12 December 2009 03:54:00 pm I=C3=B1aki Baz Castillo wrote:
> > El S=C3=A1bado, 12 de Diciembre de 2009, David Masover escribi=C3=B3:
> > > I suspect you'd have a chance to at
> > >  least fire that unlink call with any death except a 'kill -9'.
> >
> > Ok, so do you say that using "upstart" this problem could be solved as
> >  upstart itself could manage it when detects a service crash?
>=20
> I'm saying most aspects of it can be solved within the program -- anything
> except 'kill -9'. With something like upstart, even that should be
>  solvable. On OS X, I think launchd is similar. Basically, you have one (=
or
>  more) central process(es) which manage the launching and killing of
>  daemons.
>=20
> At this point, you don't even have to use pidfiles, you can just use
> variables. In pseudocode:
>=20
> class Process
>   def start
>     unless running?
>       if @pid =3D fork
>         waitpid(@pid) do
>           @pid =3D nil
>         end
>       else
>         exec @cmdline
>       end
>     end
>   end
>   def stop
>     kill @pid
>   end
> end
>=20
> The main reason that's pseudocode is that upstart very likely already does
> this for you (so why reinvent the wheel in Ruby?), and because waitpid
>  doesn't actually work that way.
>=20
> But basically, the only problem with this model is that if the process
> responsible for watching your process dies abnormally, either the pidfile
> won't be cleaned up (if there is one), or you'll now have an unmonitored
>  copy of your process running (so you'll need something like killall
>  again). If you're using something like upstart, that's not really a
>  problem -- remember, upstart is init, which means the second it dies, the
>  kernel panics. In other words, it doesn't die.

It's really great and makes lots of sense. The classic usage of pidfiles an=
d=20
so seems ugly and "deprecated" stuff.


> > > So, that gives you the best of both worlds -- it's actually somewhat
> > > like one of the crazier solutions I suggested.
> >
> > Great. However I'm not sure if my program would fit well as a gem. It's
> > not a library or utility but a whole http server (for XCAP protocol).
> > This is, it will have conf files into /etc directory and so. I've never
> > seen a gem that installs a server by itself and contains files in /etc.
>=20
> The usual approach I'd suggest here is, store a configfile path, something
> like the PATH variable, in which later configfiles override values set by
> earlier ones. Then, set all the default values in a sample config file
>  inside your gem, and let the admin put a conf file in /etc/rb_app (or in
>  ~/.rb_app,

But can a gem installation generate a default conf file/directory in /etc?
I know gem installations can generate runnable files into /usr/bin (or=20
/usr/local/bin). This is, I wouldn't like that the user has to create by=20
himself the config fiel/directory in /etc :(


>  or in a place specified by the environment variable
>  RB_APP_CONFIG, or in a place specified by --config on the commandline) if
>  they want to override something.

I like --config option as I already have command line options for chossing=
=20
logging directory, process uid/gid, listening port and so. Command line=20
options override values in the configuration file.



> On the other hand, you might consider just building a Debian package,
> depending on the interpreter you want, and hardcoding it into the shebang
>  and the upstart scripts.

The problem is that my server requires 6-7 gems and modern version of them=
=20
(for example Debian Lenny just includes Rack version 0.3 !! while current g=
em=20
version is 1.0.1 !!).


>  Let people download the source if they want to
>  tweak it further. But I'd only go this route if you're content to depend
>  on the Ruby libraries that are already packaged in Debian -- unlike some
>  other package managers, apt lacks a way to depend directly on truly alien
>  packages. (Contrast to Gobo, in which system packages can depend directly
>  on gems, CPAN modules, etc -- I know Gentoo could depend on CPAN modules,
>  too.)

This is the reason why I prefer to build a Gem rather than a deb package.=20
Creating the former would require package all the gems withing the deb pack=
age=20
which would make difficult to upgrade gems and so.

Well, after this good thread (thanks a lot) I think I'll do the following:

=2D A gem package depending on others gems (as usual).
=2D Some runnable Ruby scripts (built into the gem) like:
  - myprogram_create_conf.rb:      Creates conf files under /etc.
  - myprogram_create_init.rb:      Creates the init script.
  - myprogram_create_database.rb:  Creates database for the server.

These scripts could have different behaviour depending on the detected Linu=
x=20
distribution, this is, when running "myprogram_create_init.rb" would detect=
=20
the Linux distribution and offer different kinds of init scripts (and why n=
ot:=20
a upstart script for Ubuntu/Debian !).

Thanks a lot!


=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/12/2009 11:29:25 PM

El S=C3=A1bado, 12 de Diciembre de 2009, Shot (Piotr Szotkowski) escribi=C3=
=B3:
> I=C3=B1aki Baz Castillo:
> > However in /proc/PID/status I still have the same described
> > issues: "Name: ruby1.9", so I cannot do "killall rb_program".
> >
> > This can be solved by using:
> >   #!/usr/local/bin/ruby1.9
> > rather than:
> >   #!/usr/bin/env ruby1.9
> >
> > but of course hardcoding the location of ruby is not very good
> > approach (specially when you want your code to run on any Linux
> > system).
>=20
> I was wondering about exactly this problem recently. I=E2=80=99m using
> hand-rolled Ruby 1.9.1 and 1.8.7 versions in ~/opt =E2=80=93 and once I f=
inally
> got to rolling my own gem I found out that when RubyGems install an
> executable, they put a wrapper script in the given Ruby installation
> path, with the hashbang hardcoded to that interpreter=E2=80=99s binary.

I suffer same issues. I've installed ruby 1.9.1 (installed from sources) un=
der=20
/usr/local. and ruby 1.8.7 (Debian package) under /usr.

I compile ruby1.9 with these options:
  /configure --prefix=3D/usr/local/ --program-suffix=3D1.9 ; make ; make in=
stall
so all its runnable files are sufixed by 1.9 (ruby1.9, gem1.9, irb1.9...).

Unfortunatelly executables installed by gems are not sufixed so there is=20
conflict between ruby1.8 gems and ruby1.9 gems.

By default /usr/local/bin/ appears before than /usr/bin/ in usual PATH=20
environment variable, so executables belonging to ruby1.9 gems take=20
preference. This is ugly when you install a ruby1.8 gem which requires some=
=20
ruby executtable (as racc, rake and so).

So finally my "solution/workaround" is a script that rewrites the PATH=20
variable and sets /usr/bin/ before /usr/local/bin/. And I must run it befor=
e=20
installing a gem for ruby1.8. Ugly but works :)


> In other words =E2=80=93 while the executables in my repo start with
> =E2=80=98#!/usr/bin/env ruby=E2=80=99 (and so pick up the =E2=80=98curren=
t=E2=80=99 Ruby interpreter),
> once I roll and install a gem RubyGems create a custom executable
> wrappers for them, and the ones installed with Ruby 1.9.1 start with
> =E2=80=98#!/home/shot/opt/ruby-1.9.1-p376/bin/ruby=E2=80=99 (and if I lin=
k them from
> my ~/bin I don=E2=80=99t even need to do any $PATH munging to get them ru=
nning
> through a given Ruby binary).
>=20
> Hence, my conclusion is that if you turned your code into a gem prior
> to installing it, you could still keep the =E2=80=98#!/usr/bin/env ruby1.=
9=E2=80=99
> hashbang in your repo (and for testing), but once you want to get
> a given version into =E2=80=98production=E2=80=99, RubyGems will turn tha=
t into
> =E2=80=98#!/usr/local/bin/ruby1.9=E2=80=99 upon the gem=E2=80=99s install=
ation.

Ok, I'll do it.
Thanks a lot.


=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/12/2009 11:36:30 PM

El S=E1bado, 12 de Diciembre de 2009, Robert Klemme escribi=F3:
> This is what I would do:
>=20
> VAR=3D'/var/run'
>=20
> pid_file =3D File.join(VAR, File.basename($0) + '.pid')
>=20
> begin
>    old_pid =3D File.read(pid_file).to_i
>    Process.kill 0, old_pid
>    $stderr.puts "ERROR: already running with PID #{old_pid}"
>    exit 1
> rescue Errno::ENOENT
>    # no pid file
> rescue Errno::ESRCH
>    # process not running
>    $stderr.puts 'WARNING: stale pid file'
> end
>=20
> # open file with EXCL in order to catch race conditions where two
> # processes were started almost at the same time and both thought
> # they would be a new instance.  Uncomment sleep to simulate:
> # sleep 2
> File.open(pid_file, File::EXCL | File::WRONLY | File::CREAT) {|io|=20
> io.write($$)}
> trap(0) {File.delete pid_file}
>=20
> puts "OK, here we go."


Let me a question: is the above a fragment of a Linux init script written i=
n=20
Ruby (rather than bash/sh as usual)?

If so, according to LSB specifications it should return 0 (success) in case=
 of=20
"start" action when the daemon is already running.

Thanks a lot.


=2D-=20
I=F1aki Baz Castillo <ibc@aliax.net>

0
Reply iso 12/12/2009 11:51:02 PM

On Saturday 12 December 2009 05:29:25 pm I=C3=B1aki Baz Castillo wrote:
> El S=C3=A1bado, 12 de Diciembre de 2009, David Masover escribi=C3=B3:
> > The usual approach I'd suggest here is, store a configfile path,
> > something like the PATH variable, in which later configfiles override
> > values set by earlier ones. Then, set all the default values in a sample
> > config file inside your gem, and let the admin put a conf file in
> > /etc/rb_app (or in ~/.rb_app,
>=20
> But can a gem installation generate a default conf file/directory in /etc?

Short answer: no.

> I know gem installations can generate runnable files into /usr/bin (or
> /usr/local/bin).

No, they can't.

What they can do is provide a runnable file, which the gem system installs =
to=20
wherever it's configured to install to. I have a completely separate user f=
or=20
each version of Ruby I install, each with their own gems -- my 1.9 rubygems=
=20
install their scripts to /home/ruby19/home/bin.

I like that, because it's easy enough to add and remove PATH elements, yet =
if=20
something goes horribly wrong, I can always completely blow away=20
/home/ruby19/home (the GEM_HOME path) and rebuild it. If I'd let it install=
=20
binaries to the system path (/usr/bin or /usr/local/bin), it'd be much hard=
er=20
to sort out which were installed by gems and which weren't, unless I was=20
willing to manually uninstall each one. But part of the point of doing it t=
his=20
way is that Rubygems itself might break, so that doesn't really work.

So, basically, right now, Rubygems has explicit support for installing scri=
pts=20
into _somewhere_ in your path, just as it has explicit support for installi=
ng=20
libraries into _somewhere_ into $: -- and in both cases, you, as a gem=20
developer, have no control over where that will eventually be.

> This is, I wouldn't like that the user has to create by
> himself the config fiel/directory in /etc :(

That's why I suggested creating a script that doesn't run on installation, =
but=20
at the user's discretion. Or you could have it run when the app first launc=
hes=20
=2D- Wine is like that.

It looks like that's what you decided to do, though.

0
Reply David 12/12/2009 11:57:34 PM

El Domingo, 13 de Diciembre de 2009, David Masover escribi=C3=B3:
> On Saturday 12 December 2009 05:29:25 pm I=C3=B1aki Baz Castillo wrote:
> > El S=C3=A1bado, 12 de Diciembre de 2009, David Masover escribi=C3=B3:
> > > The usual approach I'd suggest here is, store a configfile path,
> > > something like the PATH variable, in which later configfiles override
> > > values set by earlier ones. Then, set all the default values in a
> > > sample config file inside your gem, and let the admin put a conf file
> > > in /etc/rb_app (or in ~/.rb_app,
> >
> > But can a gem installation generate a default conf file/directory in
> > /etc?
>=20
> Short answer: no.
>=20
> > I know gem installations can generate runnable files into /usr/bin (or
> > /usr/local/bin).
>=20
> No, they can't.
>=20
> What they can do is provide a runnable file, which the gem system installs
>  to wherever it's configured to install to. I have a completely separate
>  user for each version of Ruby I install, each with their own gems -- my
>  1.9 rubygems install their scripts to /home/ruby19/home/bin.
>=20
> I like that, because it's easy enough to add and remove PATH elements, yet
>  if something goes horribly wrong, I can always completely blow away
> /home/ruby19/home (the GEM_HOME path) and rebuild it. If I'd let it insta=
ll
> binaries to the system path (/usr/bin or /usr/local/bin), it'd be much
>  harder to sort out which were installed by gems and which weren't, unless
>  I was willing to manually uninstall each one. But part of the point of
>  doing it this way is that Rubygems itself might break, so that doesn't
>  really work.
>=20
> So, basically, right now, Rubygems has explicit support for installing
>  scripts into _somewhere_ in your path, just as it has explicit support f=
or
>  installing libraries into _somewhere_ into $: -- and in both cases, you,
>  as a gem developer, have no control over where that will eventually be.

Clear now, thanks a lot.


> > This is, I wouldn't like that the user has to create by
> > himself the config fiel/directory in /etc :(
>=20
> That's why I suggested creating a script that doesn't run on installation,
>  but at the user's discretion. Or you could have it run when the app first
>  launches -- Wine is like that.
>=20
> It looks like that's what you decided to do, though.
=20
Yes, thanks to this thread :)



=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/13/2009 12:52:13 AM

On 13.12.2009 00:51, I=F1aki Baz Castillo wrote:
> El S=E1bado, 12 de Diciembre de 2009, Robert Klemme escribi=F3:
>> This is what I would do:
>>
>> VAR=3D'/var/run'
>>
>> pid_file =3D File.join(VAR, File.basename($0) + '.pid')
>>
>> begin
>>     old_pid =3D File.read(pid_file).to_i
>>     Process.kill 0, old_pid
>>     $stderr.puts "ERROR: already running with PID #{old_pid}"
>>     exit 1
>> rescue Errno::ENOENT
>>     # no pid file
>> rescue Errno::ESRCH
>>     # process not running
>>     $stderr.puts 'WARNING: stale pid file'
>> end
>>
>> # open file with EXCL in order to catch race conditions where two
>> # processes were started almost at the same time and both thought
>> # they would be a new instance.  Uncomment sleep to simulate:
>> # sleep 2
>> File.open(pid_file, File::EXCL | File::WRONLY | File::CREAT) {|io|
>> io.write($$)}
>> trap(0) {File.delete pid_file}
>>
>> puts "OK, here we go."
>
>
> Let me a question: is the above a fragment of a Linux init script writt=
en in
> Ruby (rather than bash/sh as usual)?

That was hacked together for demonstration purposes.  It was not=20
intended as an init script but rather as the demon itself - albeit=20
without all the demonization stuff (detaching from terminal etc.)=20
because I wanted to focus on the aspect of pid file handling and killing.=


> If so, according to LSB specifications it should return 0 (success) in =
case of
> "start" action when the daemon is already running.

Well, if you write a start script for that "ruby demon" you would have=20
to handle exit codes properly.

Kind regards

	robert


--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

0
Reply Robert 12/13/2009 11:10:02 AM

El Domingo, 13 de Diciembre de 2009, Robert Klemme escribi=F3:
> On 13.12.2009 00:51, I=F1aki Baz Castillo wrote:
> > El S=E1bado, 12 de Diciembre de 2009, Robert Klemme escribi=F3:
> >> This is what I would do:
> >>
> >> VAR=3D'/var/run'
> >>
> >> pid_file =3D File.join(VAR, File.basename($0) + '.pid')
> >>
> >> begin
> >>     old_pid =3D File.read(pid_file).to_i
> >>     Process.kill 0, old_pid
> >>     $stderr.puts "ERROR: already running with PID #{old_pid}"
> >>     exit 1
> >> rescue Errno::ENOENT
> >>     # no pid file
> >> rescue Errno::ESRCH
> >>     # process not running
> >>     $stderr.puts 'WARNING: stale pid file'
> >> end
> >>
> >> # open file with EXCL in order to catch race conditions where two
> >> # processes were started almost at the same time and both thought
> >> # they would be a new instance.  Uncomment sleep to simulate:
> >> # sleep 2
> >> File.open(pid_file, File::EXCL | File::WRONLY | File::CREAT) {|io|
> >> io.write($$)}
> >> trap(0) {File.delete pid_file}
> >>
> >> puts "OK, here we go."
> >
> > Let me a question: is the above a fragment of a Linux init script writt=
en
> > in Ruby (rather than bash/sh as usual)?
>=20
> That was hacked together for demonstration purposes.  It was not
> intended as an init script but rather as the demon itself - albeit
> without all the demonization stuff (detaching from terminal etc.)
> because I wanted to focus on the aspect of pid file handling and killing.

Ok ok, I just asked as curiosity because some time ago I tryed to do a init=
=20
script in Ruby and couldn't do it properly... not remember the reason right=
=20
now...


> > If so, according to LSB specifications it should return 0 (success) in
> > case of "start" action when the daemon is already running.
>=20
> Well, if you write a start script for that "ruby demon" you would have
> to handle exit codes properly.

Ok, so later the init script could get "1" and return "0" as LSB states.

Thanks a lot again.

=2D-=20
I=F1aki Baz Castillo <ibc@aliax.net>

0
Reply iso 12/13/2009 12:55:43 PM

El Domingo, 13 de Diciembre de 2009, Shot (Piotr Szotkowski) escribi=C3=B3:
> I=C3=B1aki Baz Castillo:
> > I suffer same issues. I've installed ruby 1.9.1 (installed from
> > sources) under /usr/local. and ruby 1.8.7 (Debian package) under /usr.
> >
> > I compile ruby1.9 with these options:
> >   /configure --prefix=3D/usr/local/ --program-suffix=3D1.9 ; make ; make
> > install so all its runnable files are sufixed by 1.9 (ruby1.9, gem1.9,
> > irb1.9...).
>=20
> I think a much simpler solutions are to either (a) use rvm (which
> doesn=E2=80=99t work for me for some reason) or (b) use my approach (belo=
w).
>=20
> I don=E2=80=99t use program suffixes, but rather use
>=20
> ./configure --prefix=3D/home/shot/opt/ruby-1.9.1-p376
>=20
> (and similar, for example ~/opt/ruby-1.8.7-git when building 1.8.7 from
> the repo=E2=80=99s latest 1.8.7 revision) plus ~/opt/ruby-1.8 and ~/opt/r=
uby-1.9
> symlinks poiting to the hand-compiled versions I want to use for my
> development. I then have
>=20
> export PATH_ORIG=3D"$PATH"
>=20
> at the end of my ~/.bashrc and
>=20
> alias r18=3D'export PATH=3D/home/shot/opt/ruby-1.8/bin:$PATH_ORIG'
> alias r19=3D'export PATH=3D/home/shot/opt/ruby-1.9/bin:$PATH_ORIG'
>=20
> in my ~/.bash_aliases, and switching between Ruby 1.8 and 1.9 is as
> quick as running =E2=80=98r18=E2=80=99 and =E2=80=98r19=E2=80=99 in the s=
hell. I leave system-packaged
> Ruby alone, if only so that =E2=80=98gem update --system=E2=80=99 works s=
anely (and so
> no sudo is required for any of my Ruby development whatsoever).
>=20
> Of course, if you want to have system-wide hand-compiled Ruby 1.8 and/or
> 1.9, putting them in /opt (rather than ~/opt) might be more elegant.

This is a very nice solution. However the problem is that I need ruby1.8 de=
b=20
package isntalled in my system as many other packages require ruby1.8, and =
it=20
is installed under /usr/ as usual.


=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/13/2009 12:56:03 PM

On 13.12.2009 13:55, I=F1aki Baz Castillo wrote:
> El Domingo, 13 de Diciembre de 2009, Robert Klemme escribi=F3:
>> On 13.12.2009 00:51, I=F1aki Baz Castillo wrote:
>>> El S=E1bado, 12 de Diciembre de 2009, Robert Klemme escribi=F3:
>>>> This is what I would do:
>>>>
>>>> VAR=3D'/var/run'
>>>>
>>>> pid_file =3D File.join(VAR, File.basename($0) + '.pid')
>>>>
>>>> begin
>>>>     old_pid =3D File.read(pid_file).to_i
>>>>     Process.kill 0, old_pid
>>>>     $stderr.puts "ERROR: already running with PID #{old_pid}"
>>>>     exit 1
>>>> rescue Errno::ENOENT
>>>>     # no pid file
>>>> rescue Errno::ESRCH
>>>>     # process not running
>>>>     $stderr.puts 'WARNING: stale pid file'
>>>> end
>>>>
>>>> # open file with EXCL in order to catch race conditions where two
>>>> # processes were started almost at the same time and both thought
>>>> # they would be a new instance.  Uncomment sleep to simulate:
>>>> # sleep 2
>>>> File.open(pid_file, File::EXCL | File::WRONLY | File::CREAT) {|io|
>>>> io.write($$)}
>>>> trap(0) {File.delete pid_file}
>>>>
>>>> puts "OK, here we go."
>>> Let me a question: is the above a fragment of a Linux init script wri=
tten
>>> in Ruby (rather than bash/sh as usual)?
>> That was hacked together for demonstration purposes.  It was not
>> intended as an init script but rather as the demon itself - albeit
>> without all the demonization stuff (detaching from terminal etc.)
>> because I wanted to focus on the aspect of pid file handling and killi=
ng.
>=20
> Ok ok, I just asked as curiosity because some time ago I tryed to do a =
init=20
> script in Ruby and couldn't do it properly... not remember the reason r=
ight=20
> now...

One small thing just comes to mind: you can replace the "trap(0) {..."=20
with "at_exit {...".  This is probably a bit more rubyish.  It also has=20
the advantage that you can have multiple at_exit handlers while you can=20
only have one trap:

robert@fussel ~
$ ruby19 -e '2.times {|i| at_exit { puts "exiting #{i}..."} }'
exiting 1...
exiting 0...

robert@fussel ~
$ ruby19 -e '2.times {|i| trap(0) { puts "exiting #{i}..."} }'
exiting 1...

robert@fussel ~
$

>>> If so, according to LSB specifications it should return 0 (success) i=
n
>>> case of "start" action when the daemon is already running.
>> Well, if you write a start script for that "ruby demon" you would have=

>> to handle exit codes properly.
>=20
> Ok, so later the init script could get "1" and return "0" as LSB states=
=2E

Exactly.

> Thanks a lot again.

You're welcome!

Kind regards

	robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
0
Reply Robert 12/13/2009 2:05:06 PM

24 Replies
126 Views

(page loaded in 0.181 seconds)

Similiar Articles:







7/26/2012 12:17:02 AM


Reply: