4 use vars qw( $DEBUG $kids $max_kids %kids );
5 use POSIX qw(:sys_wait_h);
7 use FS::UID qw(adminsuidsetup forksuidsetup driver_name dbh myconnect);
8 use FS::Daemon qw(daemonize1 drop_root logfile daemonize2 sigint sigterm);
9 use FS::Record qw(qsearch qsearchs);
14 # no autoloading for non-FS classes...
19 $max_kids = '10'; #guess it should be a config file...
22 my $user = shift or die &usage;
24 warn "starting daemonization (forking)\n" if $DEBUG;
25 #daemonize1('freeside-queued',$user); #to keep pid files unique w/multi installs
26 daemonize1('freeside-queued');
28 warn "dropping privledges\n" if $DEBUG;
32 $ENV{HOME} = (getpwuid($>))[7]; #for ssh
34 warn "connecting to database\n" if $DEBUG;
37 eval { adminsuidsetup $user; };
40 warn "sleeping for reconnect...\n";
45 logfile( "%%%FREESIDE_LOG%%%/queuelog.". $FS::UID::datasrc );
47 warn "completing daemonization (detaching))\n" if $DEBUG;
56 #prevent runaway forking
57 if ( $kids >= $max_kids ) {
58 warn "WARNING: maximum $kids children reached\n" unless $warnkids++;
60 sleep 1; #waiting for signals is cheap
65 unless ( dbh && dbh->ping ) {
66 warn "WARNING: connection to database lost, reconnecting...\n";
68 eval { $FS::UID::dbh = myconnect; };
70 unless ( !$@ && dbh && dbh->ping ) {
71 warn "WARNING: still no connection to database, sleeping for retry...\n";
75 warn "WARNING: reconnected to database\n";
81 # my $oldAutoCommit = $FS::UID::AutoCommit;
82 # local $FS::UID::AutoCommit = 0;
83 $FS::UID::AutoCommit = 0;
85 #assuming mysql 4.1 w/subqueries now
86 #my $nodepend = driver_name eq 'mysql'
88 # : 'AND 0 = ( SELECT COUNT(*) FROM queue_depend'.
89 # ' WHERE queue_depend.jobnum = queue.jobnum ) ';
90 my $nodepend = 'AND 0 = ( SELECT COUNT(*) FROM queue_depend'.
91 ' WHERE queue_depend.jobnum = queue.jobnum ) ';
95 { 'status' => 'new' },
97 driver_name eq 'mysql'
98 ? "$nodepend ORDER BY jobnum LIMIT 1 FOR UPDATE"
99 : "$nodepend ORDER BY jobnum FOR UPDATE LIMIT 1"
101 # if $oldAutoCommit {
103 warn "WARNING: database error, closing connection: ". dbh->errstr;
108 sleep 5; #connecting to db is expensive
112 #assuming mysql 4.1 w/subqueries now
113 #if ( driver_name eq 'mysql'
114 # && qsearch('queue_depend', { 'jobnum' => $job->jobnum } ) ) {
115 # dbh->commit or die dbh->errstr; #if $oldAutoCommit;
116 # sleep 5; #would be better if mysql could do everything in query above
120 my %hash = $job->hash;
121 $hash{'status'} = 'locked';
122 my $ljob = new FS::queue ( \%hash );
123 my $error = $ljob->replace($job);
125 warn "WARNING: database error locking job, closing connection: ".
131 # if $oldAutoCommit {
133 warn "WARNING: database error, closing connection: ". dbh->errstr;
139 $FS::UID::AutoCommit = 1;
142 my @args = $ljob->args;
143 splice @args, 0, 1, $ljob if $args[0] eq '_JOB';
145 defined( my $pid = fork ) or do {
146 warn "WARNING: can't fork: $!\n";
147 my %hash = $job->hash;
148 $hash{'status'} = 'failed';
149 $hash{'statustext'} = "[freeside-queued] can't fork: $!";
150 my $ljob = new FS::queue ( \%hash );
151 my $error = $ljob->replace($job);
152 die $error if $error;
153 next; #don't increment the kid counter
162 $FS::UID::dbh->{InactiveDestroy} = 1;
164 forksuidsetup($user);
167 #if ( $ljob->job =~ /(FS::part_export::\w+)::/ ) {
168 if ( $ljob->job =~ /(FS::part_export::\w+)::/
169 || $ljob->job =~ /(FS::\w+)::/
175 warn "job use $class failed";
176 my %hash = $ljob->hash;
177 $hash{'status'} = 'failed';
178 $hash{'statustext'} = $@;
179 my $fjob = new FS::queue( \%hash );
180 my $error = $fjob->replace($ljob);
181 die $error if $error;
186 my $eval = "&". $ljob->job. '(@args);';
187 warn 'running "&'. $ljob->job. '('. join(', ', @args). ")\n" if $DEBUG;
188 eval $eval; #throw away return value? suppose so
190 warn "job $eval failed";
191 my %hash = $ljob->hash;
192 $hash{'status'} = 'failed';
193 $hash{'statustext'} = $@;
194 my $fjob = new FS::queue( \%hash );
195 my $error = $fjob->replace($ljob);
196 die $error if $error;
207 warn "received TERM signal; exiting\n";
211 warn "received INT signal; exiting\n";
217 die "Usage:\n\n freeside-queued user\n";
221 foreach my $pid ( keys %kids ) {
222 my $kid = waitpid($pid, WNOHANG);
232 freeside-queued - Job queue daemon
240 Job queue daemon. Should be running at all times.
242 user: from the mapsecrets file - see config.html from the base documentation