aboutsummaryrefslogtreecommitdiff
path: root/Bugzilla/JobQueue/Runner.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla/JobQueue/Runner.pm')
-rw-r--r--Bugzilla/JobQueue/Runner.pm237
1 files changed, 237 insertions, 0 deletions
diff --git a/Bugzilla/JobQueue/Runner.pm b/Bugzilla/JobQueue/Runner.pm
new file mode 100644
index 0000000..8b5cf9b
--- /dev/null
+++ b/Bugzilla/JobQueue/Runner.pm
@@ -0,0 +1,237 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+# XXX In order to support Windows, we have to make gd_redirect_output
+# use Log4Perl or something instead of calling "logger". We probably
+# also need to use Win32::Daemon or something like that to daemonize.
+
+package Bugzilla::JobQueue::Runner;
+
+use strict;
+use Cwd qw(abs_path);
+use File::Basename;
+use File::Copy;
+use Pod::Usage;
+
+use Bugzilla::Constants;
+use Bugzilla::JobQueue;
+use Bugzilla::Util qw(get_text);
+BEGIN { eval "use base qw(Daemon::Generic)"; }
+
+our $VERSION = BUGZILLA_VERSION;
+
+# Info we need to install/uninstall the daemon.
+our $chkconfig = "/sbin/chkconfig";
+our $initd = "/etc/init.d";
+our $initscript = "bugzilla-queue";
+
+# The Daemon::Generic docs say that it uses all sorts of
+# things from gd_preconfig, but in fact it does not. The
+# only thing it uses from gd_preconfig is the "pidfile"
+# config parameter.
+sub gd_preconfig {
+ my $self = shift;
+
+ $self->{_run_command} = 'subprocess_worker';
+ my $pidfile = $self->{gd_args}{pidfile};
+ if (!$pidfile) {
+ $pidfile = bz_locations()->{datadir} . '/' . $self->{gd_progname}
+ . ".pid";
+ }
+ return (pidfile => $pidfile);
+}
+
+# All config other than the pidfile has to be done in gd_getopt
+# in order for it to be set up early enough.
+sub gd_getopt {
+ my $self = shift;
+
+ $self->SUPER::gd_getopt();
+
+ if ($self->{gd_args}{progname}) {
+ $self->{gd_progname} = $self->{gd_args}{progname};
+ }
+ else {
+ $self->{gd_progname} = basename($0);
+ }
+
+ # There are places that Daemon Generic's new() uses $0 instead of
+ # gd_progname, which it really shouldn't, but this hack fixes it.
+ $self->{_original_zero} = $0;
+ $0 = $self->{gd_progname};
+}
+
+sub gd_postconfig {
+ my $self = shift;
+ # See the hack above in gd_getopt. This just reverses it
+ # in case anything else needs the accurate $0.
+ $0 = delete $self->{_original_zero};
+}
+
+sub gd_more_opt {
+ my $self = shift;
+ return (
+ 'pidfile=s' => \$self->{gd_args}{pidfile},
+ 'n=s' => \$self->{gd_args}{progname},
+ );
+}
+
+sub gd_usage {
+ pod2usage({ -verbose => 0, -exitval => 'NOEXIT' });
+ return 0
+}
+
+sub gd_can_install {
+ my $self = shift;
+
+ my $source_file;
+ if ( -e "/etc/SuSE-release" ) {
+ $source_file = "contrib/$initscript.suse";
+ } else {
+ $source_file = "contrib/$initscript.rhel";
+ }
+ my $dest_file = "$initd/$initscript";
+ my $sysconfig = '/etc/sysconfig';
+ my $config_file = "$sysconfig/$initscript";
+
+ if (!-x $chkconfig or !-d $initd) {
+ return $self->SUPER::gd_can_install(@_);
+ }
+
+ return sub {
+ if (!-w $initd) {
+ print "You must run the 'install' command as root.\n";
+ return;
+ }
+ if (-e $dest_file) {
+ print "$initscript already in $initd.\n";
+ }
+ else {
+ copy($source_file, $dest_file)
+ or die "Could not copy $source_file to $dest_file: $!";
+ chmod(0755, $dest_file)
+ or die "Could not change permissions on $dest_file: $!";
+ }
+
+ system($chkconfig, '--add', $initscript);
+ print "$initscript installed.",
+ " To start the daemon, do \"$dest_file start\" as root.\n";
+
+ if (-d $sysconfig and -w $sysconfig) {
+ if (-e $config_file) {
+ print "$config_file already exists.\n";
+ return;
+ }
+
+ open(my $config_fh, ">", $config_file)
+ or die "Could not write to $config_file: $!";
+ my $directory = abs_path(dirname($self->{_original_zero}));
+ my $owner_id = (stat $self->{_original_zero})[4];
+ my $owner = getpwuid($owner_id);
+ print $config_fh <<END;
+#!/bin/sh
+BUGZILLA="$directory"
+# This user must have write access to Bugzilla's data/ directory.
+USER=$owner
+END
+ close($config_fh);
+ }
+ else {
+ print "Please edit $dest_file to configure the daemon.\n";
+ }
+ }
+}
+
+sub gd_can_uninstall {
+ my $self = shift;
+
+ if (-x $chkconfig and -d $initd) {
+ return sub {
+ if (!-e "$initd/$initscript") {
+ print "$initscript not installed.\n";
+ return;
+ }
+ system($chkconfig, '--del', $initscript);
+ print "$initscript disabled.",
+ " To stop it, run: $initd/$initscript stop\n";
+ }
+ }
+
+ return $self->SUPER::gd_can_install(@_);
+}
+
+sub gd_check {
+ my $self = shift;
+
+ # Get a count of all the jobs currently in the queue.
+ my $jq = Bugzilla->job_queue();
+ my @dbs = $jq->bz_databases();
+ my $count = 0;
+ foreach my $driver (@dbs) {
+ $count += $driver->select_one('SELECT COUNT(*) FROM ts_job', []);
+ }
+ print get_text('job_queue_depth', { count => $count }) . "\n";
+}
+
+sub gd_setup_signals {
+ my $self = shift;
+ $self->SUPER::gd_setup_signals();
+ $SIG{TERM} = sub { $self->gd_quit_event(); }
+}
+
+sub gd_quit_event {
+ Bugzilla->job_queue->kill_worker();
+ exit(1);
+}
+
+sub gd_other_cmd {
+ my ($self, $do, $locked) = @_;
+ if ($do eq "once") {
+ $self->{_run_command} = 'work_once';
+ } elsif ($do eq "onepass") {
+ $self->{_run_command} = 'work_until_done';
+ } else {
+ $self->SUPER::gd_other_cmd($do, $locked);
+ }
+}
+
+sub gd_run {
+ my $self = shift;
+ $self->_do_work($self->{_run_command});
+}
+
+sub _do_work {
+ my ($self, $fn) = @_;
+
+ my $jq = Bugzilla->job_queue();
+ $jq->set_verbose($self->{debug});
+ $jq->set_pidfile($self->{gd_pidfile});
+ foreach my $module (values %{ Bugzilla::JobQueue->job_map() }) {
+ eval "use $module";
+ $jq->can_do($module);
+ }
+ $jq->$fn;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::JobQueue::Runner - A class representing the daemon that runs the
+job queue.
+
+=head1 SYNOPSIS
+
+ use Bugzilla::JobQueue::Runner;
+ Bugzilla::JobQueue::Runner->new();
+
+=head1 DESCRIPTION
+
+This is a subclass of L<Daemon::Generic> that is used by L<jobqueue>
+to run the Bugzilla job queue.