But I seem to have a race condition somewhere so that everything locks up on occassion, and I can't stop where it is going wrong.
The reason that the code with the lockup exists is because I want to:
Help appreciated:
# Used for getting lock in the database my $lockname = $class.'::'.$handler; # Get exclusive lock on jobs table # clear_cache deletes the cached db handles in DBI # so that the next connect should get a fresh handle MyStuff::DB::clear_cache(); my $db = MyStuff::DB->connect('default'); my $lock = $db->dbh; $lock->do('LOCK TABLES jobs WRITE'); # Get existing info for job status $db = $db->select_row({ bind => ['CHAR'], params => [$lockname], SQL => 'SELECT pid,last_id,last_run||"1970-01-01" FROM job +s WHERE name = ?' }); my $results = $db->results; # If job is still running if ($results && $results->{pid} && kill 0 => $results->{pid}) { logmsg("Still running"); $lock->do('UNLOCK TABLES'); $Starts{$lockname}++; if ($Starts{$lockname}>5) { warn "Tried to start $class => $handler $Starts{$lockname} + times"; } return; } # Start new job logmsg ("Starting '$lockname'"); my $current_time = timestamp(); # Last time the job was run # the last ID processed, or the last # time it was run was.... my $last_run = $results->{last_run} ? $results->{last_run}->strftime('%F %T') : '1970-01-01'; my $last = { id => $results->{last_id}||0, run => $last_run, time => $current_time, }; # Fork you my $pid = fork; unless (defined $pid) { warn "Couldn't fork to start $class => $handler : $!"; return; } if ($pid) { # Parent # Update jobs table with new PID # THIS IS THE POINT AT WHICH IT HANGS # AND IN THE DB LOGS, IT HAS THE SAME CONNECTION # ID AS THE HANDLE WHICH OBTAINED THE LOCK $db = $db->replace({ bind => ['CHAR','INT','INT','DATE'], params => [$lockname, $pid, $last->{id}, $last->{run}], SQL => <<SQL}); REPLACE INTO jobs ( name ,pid ,last_id ,last_run ) VALUES (?,?,?,?) SQL $lock->do('UNLOCK TABLES'); $Starts{$lockname}=0; return; } # Child # Get rid of old database connections MyStuff::DB::clear_cache(); chdir '/' or die $!; open STDIN, '/dev/null' or die $!; # Checking that my job has had my PID set for me $db = MyStuff::DB->connect('default.write'); $db->select_row({ bind => ['CHAR'], params => [$lockname], SQL => <<SQL}); SELECT pid FROM jobs WHERE name = ? SQL my $results = $db->results; unless ($results && $results->{pid} == $$) { die "Jobs table not locked for me" } # Run handler eval {$class->$handler($last,$args)}; if ($@) { die "Error running '$lockname' : $@"; } # Reset jobs table $db = MyStuff::DB->update({ db => 'default.write', bind => ['INT','DATE','CHAR','INT'], params => [$last->{id}, $last->{time}, $lockname, $$], SQL => <<SQL}); UPDATE jobs SET pid = 0 , last_id = ? , last_run = ? WHERE name = ? AND pid = ? SQL logmsg ("Ending '$lockname'"); exit 0; }
In reply to Race condition in my cron daemon by clinton
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |