IPC::ConcurrencyLimit::WithStandby - IPC::ConcurrencyLimit with an additional standby lock
use IPC::ConcurrencyLimit::WithStandby; sub run { my $limit = IPC::ConcurrencyLimit::WithStandby->new( type => 'Flock', # that's also the default max_procs => 10, path => '/var/run/myapp', standby_path => '/var/run/myapp/standby', standby_max_procs => 3, ); my $id = $limit->get_lock; if (not $id) { warn "Got none of the worker locks. Exiting."; exit(0); } else { # Got one of the worker locks (ie. number $id) do_work(); } # lock released with $limit going out of scope here } run(); exit();
This module provides the same interface as the regular IPC::ConcurrencyLimit module. It differs in what happens if get_lock fails to get a slot for the main limit:
get_lock
If it fails to get a (or the) lock on the main limit, it will repeatedly attempt to get the main lock until a slot for the main limit is attained or the number of retries is exhausted. Most importantly, this supports limiting the number of instances that continuously attempt to get the main lock (typically, this would be limited to 1). This is implemented with a wait-retry-loop and two separate IPC::ConcurrencyLimit objects.
IPC::ConcurrencyLimit
The options for the main limit are passed in to the constructor as usual. The standby limit are inherited from the main one, but all parameters prefixed with standby_ will override the respective inherited parameters. For example, standby_type => "MySQL" will enforce the use of the MySQL lock for the standby lock.
standby_
standby_type => "MySQL"
In addition to the regular IPC::ConcurrencyLimit options, the constructor accepts retries as the number of retries a standby instance should do to get the main lock. There will always be only one attempt to become a standby process. Additionally, interval can indicate a number of seconds to wait between retries (also supports fractional seconds down to what Time::HiRes::sleep supports).
retries
interval
Time::HiRes::sleep
retries can also be passed a code reference that will be called on every retry, with the current attempt number as its first argument (starting at 1). Returning false from this routine will break the loop and give up any further attempts to acquire the lock. One example of a configuration which would continue to attempt to acquire a lock forever would be as follows:
my $limit = IPC::ConcurrencyLimit::WithStandby->new( retries => sub { $_[0] }, interval => 0.01, maxproc => 1, standby_max_procs => 1, ... );
The form above would be used to have a single process running, with a standby process ready to take over 1/100th of a second after the active process exits, at the expense of attempting to acquire a flock() 100 times per second.
flock()
Finally, as a way to tell blocked worker processes apart from standby processes, the module supports the process_name_change option. If set to true, then the module will modify the process name of standby processes via modification of <$0>. It appends the string " - standby" to $0 and resets it to the old value after timing out or getting a worker lock. This is only supported on newer Perls and might not work on all operating systems. On my testing Linux, a process that showed as perl foo.pl in the process table before using this feature was shown as foo.pl - standby while in standby mode and as foo.pl after getting a main worker lock. Note the curiously stripped perl prefix.
process_name_change
perl foo.pl
foo.pl - standby
foo.pl
perl
Steffen Mueller, smueller@cpan.org
smueller@cpan.org
David Morel, david.morel@amakuru.net
david.morel@amakuru.net
This module was originally developed for booking.com. With approval from booking.com, this module was generalized and put on CPAN, for which the authors would like to express their gratitude.
(C) 2012 Steffen Mueller. All rights reserved. This code is available under the same license as Perl version 5.8.1 or higher. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
To install IPC::ConcurrencyLimit, copy and paste the appropriate command in to your terminal.
cpanm
cpanm IPC::ConcurrencyLimit
CPAN shell
perl -MCPAN -e shell install IPC::ConcurrencyLimit
For more information on module installation, please visit the detailed CPAN module installation guide.