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.)
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.