Search code examples
perlfcntl

Perl using Fcntl in multi server context


I'm trying to use Fcntl library to run only one instance of a script at a time,

It works when it's only one server who run the script (same server can't run another instance of the script), but if I have another server (who actually access the same filesystem) run the script, it doesn't work (he can actully run it).

Anyone has an idea on how to handle this using Fcntl library (or another ?)

Thanks in advance.


Solution

  • File locking is notoriously hard over NFS but it is probably overkill for what you need. Just have the server instances coordinate on a network-accessible file that will contain information about the server with the "lock".

    ...
    if (-f "/network/accessible/file.lock") {
        open my $fh, '<', "/network/accessible/file.lock";
        my $lockholder = <$fh>;
        die "Server lock held by $lockholder";
    
        # ... you could also examine $lockholder and verify that
        #     the other server is still alive ...
    } else {
        open my $fh, '>', "/network/accessible/file.lock";
        print $fh $ENV{HOSTNAME},":$$";
        close $fh;
    }
    ...
    
    # need to remove the lock when the current server finishes
    END { unlink "/network/accessible/file.lock" }
    

    This will be sufficient unless you start two servers within milliseconds of each other. If you are paranoid about that, you can have the server read the lockfile after it is created, and/or periodically throughout the program, to make sure that the lockfile information hasn't changed.

    } else {
        open my $fh, '>', "/network/accessible/file.lock";
        print $fh $ENV{HOSTNAME},":$$";
        close $fh;
    
        sleep 1;
        open $fh, '<', "/network/accessible/file.lock";
        my $lockholder = <$fh>;
        if ($lockholder ne "$ENV{HOSTNAME}:$$") {
            die "Server lock was stolen by $lockholder!";
        }
    }