Ensuring only one instance of a script is running

Hi all,

I’m probably late to the game on this, but I stumbled across an
interesting use for DATA. You can use it to ensure only one instance
of a given script is running by using flock:

class Foo
def self.mainloop
while true
puts “Looping…”
sleep 3
end
end
end

DATA.flock(File::LOCK_EX)

if $0 == FILE
Foo.mainloop
end

_END

The first run will work, but trying to start the program up again will
fail instantly because of the lock on DATA. I should probably do some
cleanup there, too, but I thought I’d toss this out there and see if
this is of interest to anyone.

Or was I was recovering from a hangover in college when they mentioned
this trick in class? Anyway, there you go.

Regards,

Dan

On May 20, 2008, at 10:25 PM, Daniel B. wrote:

The first run will work, but trying to start the program up again will
fail instantly because of the lock on DATA. I should probably do some
cleanup there, too, but I thought I’d toss this out there and see if
this is of interest to anyone.

Or was I was recovering from a hangover in college when they mentioned
this trick in class? Anyway, there you go.

quite interesting, i use self-locking scripts quite often, but DATA is
one step shorter :wink:

thanks for the tip.

a @ http://codeforpeople.com/

Daniel B. wrote:

DATA.flock(File::LOCK_EX)

Google seems to think it’s original, FWIW.

It’s kind of unusual for a new ruby idiom to show up. Yippee.

Daniel B. wrote:

Hi all,

I’m probably late to the game on this, but I stumbled across an
interesting use for DATA. You can use it to ensure only one instance
of a given script is running by using flock:

class Foo
def self.mainloop
while true
puts “Looping…”
sleep 3
end
end
end

DATA.flock(File::LOCK_EX)
I think the above is actually equal to

File.new($0).flock(File::LOCK_EX)

Regards,

Park H.

On Wed, May 21, 2008 at 10:40:49PM +0900, Daniel B. wrote:

I’ve wasted a lot of time with pid files…

Hear hear. You could also use a process manager such as daemontools or
runit -
that’s generally what I do.

On May 20, 10:45 pm, “ara.t.howard” [email protected] wrote:

quite interesting, i use self-locking scripts quite often, but DATA is
one step shorter :wink:

thanks for the tip.

You’re welcome. :slight_smile:

I’ve wasted a lot of time with pid files…

Regards,

Dan

On Wed, May 21, 2008 at 7:08 AM, Joel VanderWerf
[email protected] wrote:

Daniel B. wrote:

DATA.flock(File::LOCK_EX)

Google seems to think it’s original, FWIW.

Locking DATA has been used in Perl for a long time.

On May 25, 11:43 am, “Xavier N.” [email protected] wrote:

On Wed, May 21, 2008 at 7:08 AM, Joel VanderWerf

[email protected] wrote:

DanielBergerwrote:

DATA.flock(File::LOCK_EX)

Google seems to think it’s original, FWIW.

Locking DATA has been used in Perl for a long time.

Apparently so, because it was a use.perl blog entry that gave me the
idea. For whatever reason I never came across that idiom even while I
was mainly a Perl guy. :slight_smile:

Regards,

Dan

On Wed, May 21, 2008 at 5:25 AM, Daniel B. [email protected]
wrote:

    sleep 3

_END

Dan

Nice one! However, I don’t get a failure (on Linux) - instead the
second instance blocks waiting for the first instance to terminate at
which point it executes. Also, needing to specify END is a little
awkward IMHO.

I wonder, does the following work on Windows?

if $0 == FILE
if File.open($0).flock(File::LOCK_EX|File::LOCK_NB)
Foo.mainloop
end
end

Wrapped up in a method:

$ cat single_instance.rb
def single_instance(&block)
if File.open($0).flock(File::LOCK_EX|File::LOCK_NB)
block.call
else
warn “Script #{ $0 } is already running”
end
end

$ cat self_locking.rb
require ‘single_instance’
if FILE == $0
single_instance do
Foo.mainloop
end
end

I think I’ll use this :slight_smile:

Thanks,
Sean

On May 25, 7:46 am, “Sean O’Halpin” [email protected] wrote:

    puts "Looping..."

Regards,
if $0 == FILE
block.call
end
end

Yep, that’s definitely cleaner, thanks.

I think I’ll use this :slight_smile:

Excellent. Good to know someone found it useful. :slight_smile:

Regards,

Dan

On May 20, 11:18 pm, Heesob P. [email protected] wrote:

     puts "Looping..."
     sleep 3
  end

end
end

DATA.flock(File::LOCK_EX)

I think the above is actually equal to

File.new($0).flock(File::LOCK_EX)

It would seem so. Sean O’Halpin has expanded on it a bit, too.

Regards,

Dan

On Wed, May 21, 2008 at 01:25:08PM +0900, Daniel B. wrote:

The first run will work, but trying to start the program up again will
fail instantly because of the lock on DATA.

Cute trick.

However, I wouldn’t recommend it’s use in any distributed code. flocks
are intended to serve a purpose other than what’s achieved as a side
effect here, and although it’s generally safe, the behavior is unknown
at best if the script file resides in a remote file system like NFS.

For example, in Linux versions prior to 2.6.12 flocks are local only, so
this would have the intended effect. However, in Linux versions 2.6.12
and newer, flocks are emulated by POSIX locks, which should result in
only a single instance running across a set of machines attempting to
run the same script located in an NFS share.

On May 28, 2008, at 4:35 PM, Mike K. wrote:

this would have the intended effect. However, in Linux versions
2.6.12
and newer, flocks are emulated by POSIX locks, which should result in
only a single instance running across a set of machines attempting to
run the same script located in an NFS share.

you can use the same trick even on NFS

require ‘posixlock’ # gem install posixlock

DATA.posixlock( File::LOCK_EX | File::LOCK_NB )

and this will work for both NFS and local fs. of course you’d need to
degrade to flock if posixlock is not installed…

my lockfile gem is also NFS safe and can be used for this purpose.
actually it can make any program run one instance without modification

rlock lockifle run_this_once.rb

regards.

a @ http://codeforpeople.com/

On May 28, 5:48 pm, “ara.t.howard” [email protected] wrote:

For example, in Linux versions prior to 2.6.12 flocks are local

DATA.posixlock( File::LOCK_EX | File::LOCK_NB )

and this will work for both NFS and local fs. of course you’d need to
degrade to flock ifposixlockis not installed…

my lockfile gem is also NFS safe and can be used for this purpose.
actually it can make any program run one instance without modification

rlock lockifle run_this_once.rb

Good to know, thanks Ara.

BTW, I don’t see posixlock on the main codeforpeople file listing at
http://rubyforge.org/frs/?group_id=1024

I was able to find 0.0.1 via the RAA, though. Is that the latest
version? I ask because I want to build from source.

Thanks,

Dan