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 my $nodepend = 'AND 0 = ( SELECT COUNT(*) FROM queue_depend'.
85 ' WHERE queue_depend.jobnum = queue.jobnum )';
87 #anything with a priority goes after stuff without one
88 my $order_by = ' ORDER BY COALESCE(priority,0) ASC, jobnum ASC ';
90 $order_by .= ( driver_name eq 'mysql'
91 ? ' LIMIT 1 FOR UPDATE '
92 : ' FOR UPDATE LIMIT 1 ' );
96 'hashref' => { 'status' => 'new' },
97 'extra_sql' => $nodepend,
98 'order_by' => $order_by,
100 # if $oldAutoCommit {
102 warn "WARNING: database error, closing connection: ". dbh->errstr;
111 my %hash = $job->hash;
112 $hash{'status'} = 'locked';
113 my $ljob = new FS::queue ( \%hash );
114 my $error = $ljob->replace($job);
116 warn "WARNING: database error locking job, closing connection: ".
122 # if $oldAutoCommit {
124 warn "WARNING: database error, closing connection: ". dbh->errstr;
130 $FS::UID::AutoCommit = 1;
133 my @args = $ljob->args;
134 splice @args, 0, 1, $ljob if $args[0] eq '_JOB';
136 defined( my $pid = fork ) or do {
137 warn "WARNING: can't fork: $!\n";
138 my %hash = $job->hash;
139 $hash{'status'} = 'failed';
140 $hash{'statustext'} = "[freeside-queued] can't fork: $!";
141 my $ljob = new FS::queue ( \%hash );
142 my $error = $ljob->replace($job);
143 die $error if $error;
144 next; #don't increment the kid counter
153 $FS::UID::dbh->{InactiveDestroy} = 1;
155 forksuidsetup($user);
158 #if ( $ljob->job =~ /(FS::part_export::\w+)::/ ) {
159 if ( $ljob->job =~ /(FS::(part_export|cust_main)::\w+)::/
160 || $ljob->job =~ /(FS::\w+)::/
166 warn "job use $class failed";
167 my %hash = $ljob->hash;
168 $hash{'status'} = 'failed';
169 $hash{'statustext'} = $@;
170 my $fjob = new FS::queue( \%hash );
171 my $error = $fjob->replace($ljob);
172 die $error if $error;
177 my $eval = "&". $ljob->job. '(@args);';
178 warn 'running "&'. $ljob->job. '('. join(', ', @args). ")\n" if $DEBUG;
179 eval $eval; #throw away return value? suppose so
181 warn "job $eval failed";
182 my %hash = $ljob->hash;
183 $hash{'status'} = 'failed';
184 $hash{'statustext'} = $@;
185 my $fjob = new FS::queue( \%hash );
186 my $error = $fjob->replace($ljob);
187 die $error if $error;
198 warn "received TERM signal; exiting\n";
202 warn "received INT signal; exiting\n";
208 die "Usage:\n\n freeside-queued user\n";
212 foreach my $pid ( keys %kids ) {
213 my $kid = waitpid($pid, WNOHANG);
223 freeside-queued - Job queue daemon
231 Job queue daemon. Should be running at all times.
233 user: from the mapsecrets file - see config.html from the base documentation