Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

Re: Ensuring only one copy of a perl script is running at a time

by benizi (Hermit)
on Dec 20, 2006 at 00:21 UTC ( #590826=note: print w/ replies, xml ) Need Help??

in reply to Ensuring only one copy of a perl script is running at a time

Not sure if it's relevant to your situation, but this won't work over (some?) network filesystems. In my case, I have a home directory in AFS. Using either $0 or DATA flock'ing, it prevents two scripts on the same machine from running the same script. But, a script run from another machine proceeds as if nothing's flock'ed. I could see this being an issue if, say, a pool of webservers was serving your files.

A more robust solution might be to use a relational database system's locking mechanism. (This is often pretty convenient if you're already using a DB for other tasks.) My favorite method is to create a lock table as follows:

the MySQL:

create table foolock ( /* since we're exclusive per-program, make program primary */ program varchar(64) primary key, client varchar(255) not null, time timestamp );

and the Perl

#!/usr/bin/perl use strict; use warnings; use File::Basename; use Sys::Hostname; use DBI; my $dbh = DBI->connect('dbi:mysql:test:host','foolocker','foopass',{RaiseErr +or=>1}); my $lock_interval = 10; # minimum wait in milliseconds between attempt +s my $max_attempts = 5; # maximum number of attempts sub prog_client { ((basename $0), hostname.":$$"); } sub get_lock { sql_lock('insert into foolock (program, client) values (?,?)', pro +g_client); } sub finish_up { sql_lock('delete from foolock where program = ? and client = ?', p +rog_client); } sub sql_lock { my ($sql, @params) = @_; my $lock = $dbh->prepare_cached($sql); my $backoff = $lock_interval / 1000; for (1..$max_attempts) { my $got = eval { $dbh->do('lock tables foolock write'); $lock->execute(@params) >= 0; }; $dbh->do('unlock tables'); return 1 if $got; select undef, undef, undef, $backoff; $backoff *= 2; } return 0; } if (get_lock) { # do your thing finish_up; } else { # take appropriate action }

The get_lock and finish_up allow you to detect (via entries in the foolock table) when a script died without finishing. But, in the way it's laid out above, this prevents other processes from then acquiring locks. (Which for my task was desirable.)

Comment on Re: Ensuring only one copy of a perl script is running at a time
Select or Download Code

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://590826]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2016-05-30 16:42 GMT
Find Nodes?
    Voting Booth?