# $Id$ # -*-perl-*- use strict; use warnings; require 't/lib/db-common.pl'; use TheSchwartz; use Test::More tests => 2; # how we keep track of if job was done twice: signal from children back up to us my $work_count = 0; my $lost_race = 0; $SIG{USR1} = sub { $work_count++; }; $SIG{USR2} = sub { $lost_race ++; }; # tell our parent when we lost a race { no warnings 'once'; $TheSchwartz::FIND_JOB_BATCH_SIZE = 2; $TheSchwartz::T_LOST_RACE = sub { $lost_race = 1; # this one's in our child process. kill 'USR2', getppid(); }; $TheSchwartz::T_AFTER_GRAB_SELECT_BEFORE_UPDATE = sub { # force the race condition to happen, at least until we've triggered it select undef, undef, undef, 0.25 unless $lost_race; }; } # kill children on exit my %children; # pid -> 1 END { my @pids = keys %children; kill -9, @pids if @pids; } my $jobs = 40; run_tests_innodb(2, sub { # get one job into database, to see if children do it twice: { my $client = test_client(dbs => ['ts1']); for (1..$jobs) { $client->insert("Worker::Addition", { numbers => [1, 2] }) or die; } } # two children to race work(); work(); # hang out waiting for children to init/race/finish # while ($work_count < $jobs) { sleep 1; } my $now = time(); while (time < $now + 2) { sleep 1; } is($work_count, $jobs, "$jobs jobs done"); ok($lost_race, "lost the race at least once"); teardown_dbs('ts1'); }); sub work { # parent: if (my $childpid = fork()) { $children{$childpid} = 1; return; } my $client = test_client(dbs => ['ts1'], init => 0); # child: while (my $job = Worker::Addition->grab_job($client)) { eval { Worker::Addition->work($job); }; } exit 0; } ############################################################################ package Worker::Addition; use base 'TheSchwartz::Worker'; sub work { my ($class, $job) = @_; kill 'USR1', getppid(); $job->completed; } # tell framework to set 'grabbed_until' to time() + 60. because if # we can't add some numbers in 30 seconds, our process probably # failed and work should be reassigned. sub grab_for { 5 }