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);
13 # no autoloading for non-FS classes...
18 $max_kids = '10'; #guess it should be a config file...
21 my $user = shift or die &usage;
23 warn "starting daemonization (forking)\n" if $DEBUG;
24 #daemonize1('freeside-queued',$user); #to keep pid files unique w/multi installs
25 daemonize1('freeside-queued');
27 warn "dropping privledges\n" if $DEBUG;
31 $ENV{HOME} = (getpwuid($>))[7]; #for ssh
33 warn "connecting to database\n" if $DEBUG;
36 eval { adminsuidsetup $user; };
39 warn "sleeping for reconnect...\n";
44 logfile( "%%%FREESIDE_LOG%%%/queuelog.". $FS::UID::datasrc );
46 warn "completing daemonization (detaching))\n" if $DEBUG;
55 #prevent runaway forking
56 if ( $kids >= $max_kids ) {
57 warn "WARNING: maximum $kids children reached\n" unless $warnkids++;
59 sleep 1; #waiting for signals is cheap
64 unless ( dbh && dbh->ping ) {
65 warn "WARNING: connection to database lost, reconnecting...\n";
67 eval { $FS::UID::dbh = myconnect; };
69 unless ( !$@ && dbh && dbh->ping ) {
70 warn "WARNING: still no connection to database, sleeping for retry...\n";
74 warn "WARNING: reconnected to database\n";
80 # my $oldAutoCommit = $FS::UID::AutoCommit;
81 # local $FS::UID::AutoCommit = 0;
82 $FS::UID::AutoCommit = 0;
84 #assuming mysql 4.1 w/subqueries now
85 #my $nodepend = driver_name eq 'mysql'
87 # : 'AND 0 = ( SELECT COUNT(*) FROM queue_depend'.
88 # ' WHERE queue_depend.jobnum = queue.jobnum ) ';
89 my $nodepend = 'AND 0 = ( SELECT COUNT(*) FROM queue_depend'.
90 ' WHERE queue_depend.jobnum = queue.jobnum ) ';
94 { 'status' => 'new' },
96 driver_name eq 'mysql'
97 ? "$nodepend ORDER BY jobnum LIMIT 1 FOR UPDATE"
98 : "$nodepend ORDER BY jobnum FOR UPDATE LIMIT 1"
100 # if $oldAutoCommit {
102 warn "WARNING: database error, closing connection: ". dbh->errstr;
107 sleep 5; #connecting to db is expensive
111 #assuming mysql 4.1 w/subqueries now
112 #if ( driver_name eq 'mysql'
113 # && qsearch('queue_depend', { 'jobnum' => $job->jobnum } ) ) {
114 # dbh->commit or die dbh->errstr; #if $oldAutoCommit;
115 # sleep 5; #would be better if mysql could do everything in query above
119 my %hash = $job->hash;
120 $hash{'status'} = 'locked';
121 my $ljob = new FS::queue ( \%hash );
122 my $error = $ljob->replace($job);
124 warn "WARNING: database error locking job, closing connection: ".
130 # if $oldAutoCommit {
132 warn "WARNING: database error, closing connection: ". dbh->errstr;
138 $FS::UID::AutoCommit = 1;
141 my @args = $ljob->args;
142 splice @args, 0, 1, $ljob if $args[0] eq '_JOB';
144 defined( my $pid = fork ) or do {
145 warn "WARNING: can't fork: $!\n";
146 my %hash = $job->hash;
147 $hash{'status'} = 'failed';
148 $hash{'statustext'} = "[freeside-queued] can't fork: $!";
149 my $ljob = new FS::queue ( \%hash );
150 my $error = $ljob->replace($job);
151 die $error if $error;
152 next; #don't increment the kid counter
161 $FS::UID::dbh->{InactiveDestroy} = 1;
163 forksuidsetup($user);
166 #if ( $ljob->job =~ /(FS::part_export::\w+)::/ ) {
167 if ( $ljob->job =~ /(FS::(part_export|cust_main)::\w+)::/
168 || $ljob->job =~ /(FS::\w+)::/
174 warn "job use $class failed";
175 my %hash = $ljob->hash;
176 $hash{'status'} = 'failed';
177 $hash{'statustext'} = $@;
178 my $fjob = new FS::queue( \%hash );
179 my $error = $fjob->replace($ljob);
180 die $error if $error;
185 my $eval = "&". $ljob->job. '(@args);';
186 warn 'running "&'. $ljob->job. '('. join(', ', @args). ")\n" if $DEBUG;
187 eval $eval; #throw away return value? suppose so
189 warn "job $eval failed";
190 my %hash = $ljob->hash;
191 $hash{'status'} = 'failed';
192 $hash{'statustext'} = $@;
193 my $fjob = new FS::queue( \%hash );
194 my $error = $fjob->replace($ljob);
195 die $error if $error;
206 warn "received TERM signal; exiting\n";
210 warn "received INT signal; exiting\n";
216 die "Usage:\n\n freeside-queued user\n";
220 foreach my $pid ( keys %kids ) {
221 my $kid = waitpid($pid, WNOHANG);
231 freeside-queued - Job queue daemon
239 Job queue daemon. Should be running at all times.
241 user: from the mapsecrets file - see config.html from the base documentation