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 just yet
21 $max_kids = '10'; #guess it should be a config file...
24 my $user = shift or die &usage;
26 warn "starting daemonization (forking)\n" if $DEBUG;
27 #daemonize1('freeside-queued',$user); #to keep pid files unique w/multi installs
28 daemonize1('freeside-queued');
30 warn "dropping privledges\n" if $DEBUG;
34 $ENV{HOME} = (getpwuid($>))[7]; #for ssh
36 warn "connecting to database\n" if $DEBUG;
39 eval { adminsuidsetup $user; };
42 warn "sleeping for reconnect...\n";
47 logfile( "/usr/local/etc/freeside/queuelog.". $FS::UID::datasrc );
49 warn "completing daemonization (detaching))\n" if $DEBUG;
58 #prevent runaway forking
59 if ( $kids >= $max_kids ) {
60 warn "WARNING: maximum $kids children reached\n" unless $warnkids++;
62 sleep 1; #waiting for signals is cheap
67 unless ( dbh && dbh->ping ) {
68 warn "WARNING: connection to database lost, reconnecting...\n";
70 eval { $FS::UID::dbh = myconnect; };
72 unless ( !$@ && dbh && dbh->ping ) {
73 warn "WARNING: still no connection to database, sleeping for retry...\n";
77 warn "WARNING: reconnected to database\n";
83 # my $oldAutoCommit = $FS::UID::AutoCommit;
84 # local $FS::UID::AutoCommit = 0;
85 $FS::UID::AutoCommit = 0;
87 #assuming mysql 4.1 w/subqueries now
88 #my $nodepend = driver_name eq 'mysql'
90 # : 'AND 0 = ( SELECT COUNT(*) FROM queue_depend'.
91 # ' WHERE queue_depend.jobnum = queue.jobnum ) ';
92 my $nodepend = 'AND 0 = ( SELECT COUNT(*) FROM queue_depend'.
93 ' WHERE queue_depend.jobnum = queue.jobnum ) ';
97 { 'status' => 'new' },
99 driver_name eq 'mysql'
100 ? "$nodepend ORDER BY jobnum LIMIT 1 FOR UPDATE"
101 : "$nodepend ORDER BY jobnum FOR UPDATE LIMIT 1"
103 # if $oldAutoCommit {
105 warn "WARNING: database error, closing connection: ". dbh->errstr;
110 sleep 5; #connecting to db is expensive
114 #assuming mysql 4.1 w/subqueries now
115 #if ( driver_name eq 'mysql'
116 # && qsearch('queue_depend', { 'jobnum' => $job->jobnum } ) ) {
117 # dbh->commit or die dbh->errstr; #if $oldAutoCommit;
118 # sleep 5; #would be better if mysql could do everything in query above
122 my %hash = $job->hash;
123 $hash{'status'} = 'locked';
124 my $ljob = new FS::queue ( \%hash );
125 my $error = $ljob->replace($job);
127 warn "WARNING: database error locking job, closing connection: ".
133 # if $oldAutoCommit {
135 warn "WARNING: database error, closing connection: ". dbh->errstr;
141 $FS::UID::AutoCommit = 1;
144 my @args = $ljob->args;
145 splice @args, 0, 1, $ljob if $args[0] eq '_JOB';
147 defined( my $pid = fork ) or do {
148 warn "WARNING: can't fork: $!\n";
149 my %hash = $job->hash;
150 $hash{'status'} = 'failed';
151 $hash{'statustext'} = "[freeside-queued] can't fork: $!";
152 my $ljob = new FS::queue ( \%hash );
153 my $error = $ljob->replace($job);
154 die $error if $error;
155 next; #don't increment the kid counter
164 $FS::UID::dbh->{InactiveDestroy} = 1;
166 forksuidsetup($user);
169 #if ( $ljob->job =~ /(FS::part_export::\w+)::/ ) {
170 if ( $ljob->job =~ /(FS::part_export::\w+)::/
171 || $ljob->job =~ /(FS::\w+)::/
177 warn "job use $class failed";
178 my %hash = $ljob->hash;
179 $hash{'status'} = 'failed';
180 $hash{'statustext'} = $@;
181 my $fjob = new FS::queue( \%hash );
182 my $error = $fjob->replace($ljob);
183 die $error if $error;
188 my $eval = "&". $ljob->job. '(@args);';
189 warn 'running "&'. $ljob->job. '('. join(', ', @args). ")\n" if $DEBUG;
190 eval $eval; #throw away return value? suppose so
192 warn "job $eval failed";
193 my %hash = $ljob->hash;
194 $hash{'status'} = 'failed';
195 $hash{'statustext'} = $@;
196 my $fjob = new FS::queue( \%hash );
197 my $error = $fjob->replace($ljob);
198 die $error if $error;
209 warn "received TERM signal; exiting\n";
213 warn "received INT signal; exiting\n";
219 die "Usage:\n\n freeside-queued user\n";
223 foreach my $pid ( keys %kids ) {
224 my $kid = waitpid($pid, WNOHANG);
234 freeside-queued - Job queue daemon
242 Job queue daemon. Should be running at all times.
244 user: from the mapsecrets file - see config.html from the base documentation