4 use vars qw( @ISA @EXPORT_OK $DEBUG $conf $jobnums);
6 use FS::UID qw(myconnect);
8 use FS::Record qw( qsearch qsearchs dbh );
14 @ISA = qw(FS::Record);
15 @EXPORT_OK = qw( joblisting );
19 $FS::UID::callback{'FS::queue'} = sub {
27 FS::queue - Object methods for queue records
33 $record = new FS::queue \%hash;
34 $record = new FS::queue { 'column' => 'value' };
36 $error = $record->insert;
38 $error = $new_record->replace($old_record);
40 $error = $record->delete;
42 $error = $record->check;
46 An FS::queue object represents an queued job. FS::queue inherits from
47 FS::Record. The following fields are currently supported:
57 Fully-qualified subroutine name
61 Job status (new, locked, or failed)
65 Freeform text status message
73 Optional link to service (see L<FS::cust_svc>).
77 Optional link to customer (see L<FS::cust_main>).
81 Secure flag, 'Y' indicates that when using encryption, the job needs to be
82 run on a machine with the private key.
94 Creates a new job. To add the job to the database, see L<"insert">.
96 Note that this stores the hash reference, not a distinct copy of the hash it
97 points to. You can ask the object for a copy with the I<hash> method.
101 # the new method can be inherited from FS::Record, if a table method is defined
103 sub table { 'queue'; }
105 =item insert [ ARGUMENT, ARGUMENT... ]
107 Adds this record to the database. If there is an error, returns the error,
108 otherwise returns false.
110 If any arguments are supplied, a queue_arg record for each argument is also
111 created (see L<FS::queue_arg>).
115 #false laziness w/part_export.pm
117 my( $self, @args ) = @_;
119 local $SIG{HUP} = 'IGNORE';
120 local $SIG{INT} = 'IGNORE';
121 local $SIG{QUIT} = 'IGNORE';
122 local $SIG{TERM} = 'IGNORE';
123 local $SIG{TSTP} = 'IGNORE';
124 local $SIG{PIPE} = 'IGNORE';
126 my $oldAutoCommit = $FS::UID::AutoCommit;
127 local $FS::UID::AutoCommit = 0;
131 $self->custnum( $args{'custnum'} ) if $args{'custnum'};
133 my $error = $self->SUPER::insert;
135 $dbh->rollback if $oldAutoCommit;
139 foreach my $arg ( @args ) {
140 my $queue_arg = new FS::queue_arg ( {
141 'jobnum' => $self->jobnum,
144 $error = $queue_arg->insert;
146 $dbh->rollback if $oldAutoCommit;
152 warn "jobnums global is active: $jobnums\n" if $DEBUG;
153 push @$jobnums, $self->jobnum;
156 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
164 Delete this record from the database. Any corresponding queue_arg records are
172 local $SIG{HUP} = 'IGNORE';
173 local $SIG{INT} = 'IGNORE';
174 local $SIG{QUIT} = 'IGNORE';
175 local $SIG{TERM} = 'IGNORE';
176 local $SIG{TSTP} = 'IGNORE';
177 local $SIG{PIPE} = 'IGNORE';
179 my $oldAutoCommit = $FS::UID::AutoCommit;
180 local $FS::UID::AutoCommit = 0;
183 my @del = qsearch( 'queue_arg', { 'jobnum' => $self->jobnum } );
184 push @del, qsearch( 'queue_depend', { 'depend_jobnum' => $self->jobnum } );
186 my $error = $self->SUPER::delete;
188 $dbh->rollback if $oldAutoCommit;
192 foreach my $del ( @del ) {
193 $error = $del->delete;
195 $dbh->rollback if $oldAutoCommit;
200 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
206 =item replace OLD_RECORD
208 Replaces the OLD_RECORD with this one in the database. If there is an error,
209 returns the error, otherwise returns false.
213 # the replace method can be inherited from FS::Record
217 Checks all fields to make sure this is a valid job. If there is
218 an error, returns the error, otherwise returns false. Called by the insert
226 $self->ut_numbern('jobnum')
227 || $self->ut_anything('job')
228 || $self->ut_numbern('_date')
229 || $self->ut_enum('status',['', qw( new locked failed )])
230 || $self->ut_anything('statustext')
231 || $self->ut_numbern('svcnum')
233 return $error if $error;
235 $error = $self->ut_foreign_keyn('svcnum', 'cust_svc', 'svcnum');
236 $self->svcnum('') if $error;
238 $self->status('new') unless $self->status;
239 $self->_date(time) unless $self->_date;
246 Returns a list of the arguments associated with this job.
252 map $_->arg, qsearch( 'queue_arg',
253 { 'jobnum' => $self->jobnum },
261 Returns the FS::cust_svc object associated with this job, if any.
267 qsearchs('cust_svc', { 'svcnum' => $self->svcnum } );
272 Returns the FS::queue_depend objects associated with this job, if any.
273 (Dependancies that must complete before this job can be run).
279 qsearch('queue_depend', { 'jobnum' => $self->jobnum } );
282 =item depend_insert OTHER_JOBNUM
284 Inserts a dependancy for this job - it will not be run until the other job
285 specified completes. If there is an error, returns the error, otherwise
288 When using job dependancies, you should wrap the insertion of all relevant jobs
289 in a database transaction.
294 my($self, $other_jobnum) = @_;
295 my $queue_depend = new FS::queue_depend ( {
296 'jobnum' => $self->jobnum,
297 'depend_jobnum' => $other_jobnum,
299 $queue_depend->insert;
304 Returns the FS::queue_depend objects that associate other jobs with this job,
305 if any. (The jobs that are waiting for this job to complete before they can
312 qsearch('queue_depend', { 'depend_jobnum' => $self->jobnum } );
315 =item depended_delete
317 Deletes the other queued jobs (FS::queue objects) that are waiting for this
318 job, if any. If there is an error, returns the error, otherwise returns false.
322 sub depended_delete {
326 map { qsearchs('queue', { 'jobnum' => $_->jobnum } ) } $self->queue_depended
328 $error = $job->depended_delete;
329 return $error if $error;
330 $error = $job->delete;
331 return $error if $error
335 =item update_statustext VALUE
337 Updates the statustext value of this job to supplied value, in the database.
338 If there is an error, returns the error, otherwise returns false.
342 use vars qw($_update_statustext_dbh);
343 sub update_statustext {
344 my( $self, $statustext ) = @_;
345 return '' if $statustext eq $self->statustext;
346 warn "updating statustext for $self to $statustext" if $DEBUG;
348 $_update_statustext_dbh ||= myconnect;
350 my $sth = $_update_statustext_dbh->prepare(
351 'UPDATE queue set statustext = ? WHERE jobnum = ?'
352 ) or return $_update_statustext_dbh->errstr;
354 $sth->execute($statustext, $self->jobnum) or return $sth->errstr;
355 $_update_statustext_dbh->commit or die $_update_statustext_dbh->errstr;
356 $self->statustext($statustext);
359 #my $new = new FS::queue { $self->hash };
360 #$new->statustext($statustext);
361 #my $error = $new->replace($self);
362 #return $error if $error;
363 #$self->statustext($statustext);
373 =item joblisting HASHREF NOACTIONS
378 my($hashref, $noactions) = @_;
384 my @queue = qsearch( 'queue', $hashref );
385 return '' unless scalar(@queue);
387 my $p = FS::CGI::popurl(2);
389 my $html = qq!<FORM ACTION="$p/misc/queue.cgi" METHOD="POST">!.
390 FS::CGI::table(). <<END;
392 <TH COLSPAN=2>Job</TH>
397 $html .= '<TH>Account</TH>' unless $hashref->{svcnum};
400 my $dangerous = $conf->exists('queue_dangerous_controls');
404 foreach my $queue ( sort {
405 $a->getfield('jobnum') <=> $b->getfield('jobnum')
407 my $queue_hashref = $queue->hashref;
408 my $jobnum = $queue->jobnum;
411 if ( $dangerous || $queue->job !~ /^FS::part_export::/ || !$noactions ) {
412 $args = encode_entities( join(' ', $queue->args) );
417 my $date = time2str( "%a %b %e %T %Y", $queue->_date );
418 my $status = $queue->status;
419 $status .= ': '. $queue->statustext if $queue->statustext;
420 my @queue_depend = $queue->queue_depend;
421 $status .= ' (waiting for '.
422 join(', ', map { $_->depend_jobnum } @queue_depend ).
425 my $changable = $dangerous
426 || ( ! $noactions && $status =~ /^failed/ || $status =~ /^locked/ );
429 qq! ( <A HREF="$p/misc/queue.cgi?jobnum=$jobnum&action=new">retry</A> |!.
430 qq! <A HREF="$p/misc/queue.cgi?jobnum=$jobnum&action=del">remove</A> )!;
432 my $cust_svc = $queue->cust_svc;
437 <TD>$queue_hashref->{job}</TD>
443 unless ( $hashref->{svcnum} ) {
446 my $table = $cust_svc->part_svc->svcdb;
447 my $label = ( $cust_svc->label )[1];
448 $account = qq!<A HREF="../view/$table.cgi?!. $queue->svcnum.
453 $html .= "<TD>$account</TD>";
459 qq!<TD><INPUT NAME="jobnum$jobnum" TYPE="checkbox" VALUE="1"></TD>!;
470 $html .= '<BR><INPUT TYPE="submit" NAME="action" VALUE="retry selected">'.
471 '<INPUT TYPE="submit" NAME="action" VALUE="remove selected"><BR>';
486 L<FS::Record>, schema.html from the base documentation.