Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I ensure only one copy of a Perl script is running at a time?

I need to ensure that only one copy of my Perl script is running at a time. According to the suggestions here I wrote a sub to do the check:

sub check_instances {
    open my $fh, '<', $0 or die $!; 

    unless (flock($fh, LOCK_EX|LOCK_NB)) {
        print "$0 is already running. Exiting.\n";
        exit 1;
    } 
}

But it doesn't work. What can be the issue?

like image 305
planetp Avatar asked Dec 28 '22 06:12

planetp


2 Answers

You're using a lexical filehandle scoped inside the sub. When check_instances returns, the filehandle is automatically closed, which releases the lock. So you'll never see a conflict unless two copies check at exactly the same time.

Ensure that the filehandle remains open as long as the script is running (or as long as you want to maintain the lock). For example:

{
my $fh;
sub check_instances {
    return if $fh; # We already checked
    open $fh, '<', $0 or die $!; 

    unless (flock($fh, LOCK_EX|LOCK_NB)) {
        print "$0 is already running. Exiting.\n";
        exit 1;
    } 
}
} # end scope of $fh

This would also be a good place to use a state variable, if you can require Perl 5.10.

like image 86
cjm Avatar answered Jan 10 '23 04:01

cjm


You can check the process list for other instances (Proc::ProcessTable can help), but a common route taken by unix programs in many languages is to create a pid file -- see File::Pid.

like image 26
Ether Avatar answered Jan 10 '23 04:01

Ether