]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 284184: Allow Bugzilla to use an asynchronous job queue for sending mail.
authormkanat%bugzilla.org <>
Wed, 24 Dec 2008 03:43:36 +0000 (03:43 +0000)
committermkanat%bugzilla.org <>
Wed, 24 Dec 2008 03:43:36 +0000 (03:43 +0000)
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> and Mark Smith <mark@plogs.net> r=glob, a=mkanat

17 files changed:
Bugzilla.pm
Bugzilla/Config/Common.pm
Bugzilla/Config/MTA.pm
Bugzilla/DB/Mysql.pm
Bugzilla/DB/Oracle.pm
Bugzilla/DB/Pg.pm
Bugzilla/DB/Schema.pm
Bugzilla/Install/Filesystem.pm
Bugzilla/Install/Requirements.pm
Bugzilla/Job/Mailer.pm [new file with mode: 0644]
Bugzilla/JobQueue.pm [new file with mode: 0644]
Bugzilla/JobQueue/Runner.pm [new file with mode: 0644]
Bugzilla/Mailer.pm
jobqueue.pl [new file with mode: 0644]
template/en/default/admin/params/mta.html.tmpl
template/en/default/global/code-error.html.tmpl
template/en/default/global/messages.html.tmpl

index 00740682c05642a5ed0a72c5c2df8b6296165f00..12ae42bbae0a5938380582f3b7f01ed9406ef742 100644 (file)
@@ -42,6 +42,7 @@ use Bugzilla::Auth::Persist::Cookie;
 use Bugzilla::CGI;
 use Bugzilla::DB;
 use Bugzilla::Install::Localconfig qw(read_localconfig);
+use Bugzilla::JobQueue;
 use Bugzilla::Template;
 use Bugzilla::User;
 use Bugzilla::Error;
@@ -315,6 +316,12 @@ sub logout_request {
     # there. Don't rely on it: use Bugzilla->user->login instead!
 }
 
+sub job_queue {
+    my $class = shift;
+    $class->request_cache->{job_queue} ||= Bugzilla::JobQueue->new();
+    return $class->request_cache->{job_queue};
+}
+
 sub dbh {
     my $class = shift;
     # If we're not connected, then we must want the main db
@@ -714,4 +721,10 @@ Returns the local timezone of the Bugzilla installation,
 as a DateTime::TimeZone object. This detection is very time
 consuming, so we cache this information for future references.
 
+=item C<job_queue>
+
+Returns a L<Bugzilla::JobQueue> that you can use for queueing jobs.
+Will throw an error if job queueing is not correctly configured on
+this Bugzilla installation.
+
 =back
index d105d9db8335db8b8d812f851dd8bab86e30b2b2..b6aa1a108496179a2f02a5a9e34112022d0f2234 100644 (file)
@@ -49,7 +49,7 @@ use base qw(Exporter);
        check_opsys check_shadowdb check_urlbase check_webdotbase
        check_netmask check_user_verify_class check_image_converter
        check_mail_delivery_method check_notification check_utf8
-       check_bug_status check_smtp_auth
+       check_bug_status check_smtp_auth check_theschwartz_available
 );
 
 # Checking functions for the various values
@@ -335,6 +335,15 @@ sub check_smtp_auth {
     return "";
 }
 
+sub check_theschwartz_available {
+    if (!eval { require TheSchwartz; require Daemon::Generic; }) {
+        return "Using the job queue requires that you have certain Perl"
+               . " modules installed. See the output of checksetup.pl"
+               . " for more information";
+    }
+    return "";
+}
+
 # OK, here are the parameter definitions themselves.
 #
 # Each definition is a hash with keys:
index 37d99d967714c13f93b59f7bffb0add22ef924a9..c7843e286dfddcb8e4a701d32a20e6e5f5f50362 100644 (file)
@@ -57,6 +57,13 @@ sub get_param_list {
    default => 'bugzilla-daemon'
   },
 
+  {
+   name => 'use_mailer_queue',
+   type => 'b',
+   default => 0,
+   checker => \&check_theschwartz_available,
+  },
+
   {
    name => 'sendmailnow',
    type => 'b',
@@ -90,7 +97,6 @@ sub get_param_list {
    default => 7,
    checker => \&check_numeric
   },
-  
   {
    name => 'globalwatchers',
    type => 't',
index 889b1f0dacbeb467086adb822bbf82b86b87c7c6..f85bd31f1e29b1c8560818b3a63ae177295a79c4 100644 (file)
@@ -63,7 +63,7 @@ sub new {
     my ($class, $user, $pass, $host, $dbname, $port, $sock) = @_;
 
     # construct the DSN from the parameters we got
-    my $dsn = "DBI:mysql:host=$host;database=$dbname";
+    my $dsn = "dbi:mysql:host=$host;database=$dbname";
     $dsn .= ";port=$port" if $port;
     $dsn .= ";mysql_socket=$sock" if $sock;
 
@@ -79,6 +79,9 @@ sub new {
     # a prefix 'private_'. See DBI documentation.
     $self->{private_bz_tables_locked} = "";
 
+    # Needed by TheSchwartz
+    $self->{private_bz_dsn} = $dsn;
+
     bless ($self, $class);
     
     # Bug 321645 - disable MySQL strict mode, if set
index 833fce635315472a64b868daeb8a3f53c879db9c..4153751fdd47e40913ae649b34229f423dd6d2d8 100644 (file)
@@ -65,13 +65,15 @@ sub new {
     $ENV{'NLS_LANG'} = '.AL32UTF8' if Bugzilla->params->{'utf8'};
 
     # construct the DSN from the parameters we got
-    my $dsn = "DBI:Oracle:host=$host;sid=$dbname";
+    my $dsn = "dbi:Oracle:host=$host;sid=$dbname";
     $dsn .= ";port=$port" if $port;
     my $attrs = { FetchHashKeyName => 'NAME_lc',  
                   LongReadLen => ( Bugzilla->params->{'maxattachmentsize'}
                                      || 1000 ) * 1024, 
                 };
     my $self = $class->db_new($dsn, $user, $pass, $attrs);
+    # Needed by TheSchwartz
+    $self->{private_bz_dsn} = $dsn;
 
     bless ($self, $class);
 
index 66ad4b1ecd7991a8bec114b6caba70cd842fa891..18f9abf885270d53770979304e742b1086e48185 100644 (file)
@@ -60,7 +60,7 @@ sub new {
     $dbname ||= 'template1';
 
     # construct the DSN from the parameters we got
-    my $dsn = "DBI:Pg:dbname=$dbname";
+    my $dsn = "dbi:Pg:dbname=$dbname";
     $dsn .= ";host=$host" if $host;
     $dsn .= ";port=$port" if $port;
 
@@ -75,6 +75,8 @@ sub new {
     # all class local variables stored in DBI derived class needs to have
     # a prefix 'private_'. See DBI documentation.
     $self->{private_bz_tables_locked} = "";
+    # Needed by TheSchwartz
+    $self->{private_bz_dsn} = $dsn;
 
     bless ($self, $class);
 
index ed1245d98b2a137923b03cd27e94fa9d732c81f4..f11c86e75399d5e5b2e3783ffbc1df59c1192a0f 100644 (file)
@@ -1388,6 +1388,93 @@ use constant ABSTRACT_SCHEMA => {
         ],
      },
 
+    # THESCHWARTZ TABLES
+    # ------------------
+    # Note: In the standard TheSchwartz schema, most integers are unsigned,
+    # but we didn't implement unsigned ints for Bugzilla schemas, so we
+    # just create signed ints, which should be fine.
+
+    ts_funcmap => {
+        FIELDS => [
+            funcid   => {TYPE => 'INTSERIAL', PRIMARYKEY => 1, NOTNULL => 1},
+            funcname => {TYPE => 'varchar(255)', NOTNULL => 1},
+        ],
+        INDEXES => [
+            ts_funcmap_funcname_idx => {FIELDS => ['funcname'], 
+                                          TYPE => 'UNIQUE'},
+        ],
+    },
+
+    ts_job => {
+        FIELDS => [
+            # In a standard TheSchwartz schema, this is a BIGINT, but we
+            # don't have those and I didn't want to add them just for this.
+            jobid         => {TYPE => 'INTSERIAL', PRIMARYKEY => 1, 
+                              NOTNULL => 1},
+            funcid        => {TYPE => 'INT4', NOTNULL => 1},
+            # In standard TheSchwartz, this is a MEDIUMBLOB.
+            arg           => {TYPE => 'LONGBLOB'},
+            uniqkey       => {TYPE => 'varchar(255)'},
+            insert_time   => {TYPE => 'INT4'},
+            run_after     => {TYPE => 'INT4', NOTNULL => 1},
+            grabbed_until => {TYPE => 'INT4', NOTNULL => 1},
+            priority      => {TYPE => 'INT2'},
+            coalesce      => {TYPE => 'varchar(255)'},
+        ],
+        INDEXES => [
+            ts_job_funcid_idx => {FIELDS => [qw(funcid uniqkey)],
+                                  TYPE   => 'UNIQUE'},
+            # In a standard TheSchewartz schema, these both go in the other
+            # direction, but there's no reason to have three indexes that
+            # all start with the same column, and our naming scheme doesn't
+            # allow it anyhow.
+            ts_job_run_after_idx => [qw(run_after funcid)],
+            ts_job_coalesce_idx  => [qw(coalesce funcid)],
+        ],
+    },
+
+    ts_note => {
+        FIELDS => [
+            # This is a BIGINT in standard TheSchwartz schemas.
+            jobid   => {TYPE => 'INT4', NOTNULL => 1},
+            notekey => {TYPE => 'varchar(255)'},
+            value   => {TYPE => 'LONGBLOB'},
+        ],
+        INDEXES => [
+            ts_note_jobid_idx => {FIELDS => [qw(jobid notekey)], 
+                                    TYPE => 'UNIQUE'},
+        ],
+    },
+
+    ts_error => {
+        FIELDS => [
+            error_time => {TYPE => 'INT4', NOTNULL => 1},
+            jobid      => {TYPE => 'INT4', NOTNULL => 1},
+            message    => {TYPE => 'varchar(255)', NOTNULL => 1},
+            funcid     => {TYPE => 'INT4', NOTNULL => 1, DEFAULT => 0},
+        ],
+        INDEXES => [
+            ts_error_funcid_idx     => [qw(funcid error_time)],
+            ts_error_error_time_idx => ['error_time'],
+            ts_error_jobid_idx      => ['jobid'],
+        ],
+    },
+
+    ts_exitstatus => {
+        FIELDS => [
+            jobid           => {TYPE => 'INTSERIAL', PRIMARYKEY => 1,
+                                NOTNULL => 1},
+            funcid          => {TYPE => 'INT4', NOTNULL => 1, DEFAULT => 0},
+            status          => {TYPE => 'INT2'},
+            completion_time => {TYPE => 'INT4'},
+            delete_after    => {TYPE => 'INT4'},
+        ],
+        INDEXES => [
+            ts_exitstatus_funcid_idx       => ['funcid'],
+            ts_exitstatus_delete_after_idx => ['delete_after'],
+        ],
+    },
+
     # SCHEMA STORAGE
     # --------------
 
index 64783e3018dc1e25116b74a57f7b592acfaaa309..8afaa33845a3e6016de6a36c84e25431931891cf 100644 (file)
@@ -114,6 +114,7 @@ sub FILESYSTEM {
         'customfield.pl'  => { perms => $owner_executable },
         'email_in.pl'     => { perms => $ws_executable },
         'sanitycheck.pl'  => { perms => $ws_executable },
+        'jobqueue.pl'     => { perms => $owner_executable },
         'install-module.pl' => { perms => $owner_executable },
 
         'docs/makedocs.pl'   => { perms => $owner_executable },
index 19d54af7336d528a7fbfe8fe8e0f210b31c68ff0..5456fc7d4626c347aa84e9e81ae0fb5bcc59ac39 100644 (file)
@@ -231,6 +231,20 @@ sub OPTIONAL_MODULES {
         feature => 'Inbound Email'
     },
 
+    # Mail Queueing
+    {
+        package => 'TheSchwartz',
+        module  => 'TheSchwartz',
+        version => 0,
+        feature => 'Mail Queueing',
+    },
+    {
+        package => 'Daemon-Generic',
+        module  => 'Daemon::Generic',
+        version => 0,
+        feature => 'Mail Queueing',
+    },
+
     # mod_perl
     {
         package => 'mod_perl',
diff --git a/Bugzilla/Job/Mailer.pm b/Bugzilla/Job/Mailer.pm
new file mode 100644 (file)
index 0000000..a421c59
--- /dev/null
@@ -0,0 +1,56 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# Mozilla Corporation. All Rights Reserved.
+#
+# Contributor(s): 
+#   Mark Smith <mark@mozilla.com>
+#   Max Kanat-Alexander <mkanat@bugzilla.org>
+
+package Bugzilla::Job::Mailer;
+use Bugzilla::Mailer;
+BEGIN { eval "use base qw(TheSchwartz::Worker)"; }
+
+# The longest we expect a job to possibly take, in seconds.
+use constant grab_for => 300;
+# We don't want email to fail permanently very easily. Retry for 30 days.
+use constant max_retries => 725;
+
+# The first few retries happen quickly, but after that we wait an hour for
+# each retry.
+sub retry_delay {
+    my $num_retries = shift;
+    if ($num_retries < 5) {
+        return (10, 30, 60, 300, 600)[$num_retries];
+    }
+    # One hour
+    return 60*60;
+}
+
+sub work {
+    my ($class, $job) = @_;
+    my $msg = $job->arg->{msg};
+    my $success = eval { MessageToMTA($msg, 1); 1; };
+    if (!$success) {
+        $job->failed($@);
+        undef $@;
+    } 
+    else {
+        $job->completed;
+    }
+}
+
+1;
diff --git a/Bugzilla/JobQueue.pm b/Bugzilla/JobQueue.pm
new file mode 100644 (file)
index 0000000..102f58b
--- /dev/null
@@ -0,0 +1,108 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# Mozilla Corporation. All Rights Reserved.
+#
+# Contributor(s): 
+#   Mark Smith <mark@mozilla.com>
+#   Max Kanat-Alexander <mkanat@bugzilla.org>
+
+package Bugzilla::JobQueue;
+
+use strict;
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Install::Util qw(install_string);
+BEGIN { eval "use base qw(TheSchwartz)"; }
+
+# This maps job names for Bugzilla::JobQueue to the appropriate modules.
+# If you add new types of jobs, you should add a mapping here.
+use constant JOB_MAP => {
+    send_mail => 'Bugzilla::Job::Mailer',
+};
+
+sub new {
+    my $class = shift;
+
+    if (!eval { require TheSchwartz; }) {
+        ThrowCodeError('jobqueue_not_configured');
+    }
+
+    my $lc = Bugzilla->localconfig;
+    my $self = $class->SUPER::new(
+        databases => [{
+            dsn    => Bugzilla->dbh->{private_bz_dsn},
+            user   => $lc->{db_user},
+            pass   => $lc->{db_pass},
+            prefix => 'ts_',
+        }],
+    );
+
+    return $self;
+}
+
+# A way to get access to the underlying databases directly.
+sub bz_databases {
+    my $self = shift;
+    my @hashes = keys %{ $self->{databases} };
+    return map { $self->driver_for($_) } @hashes;
+}
+
+# inserts a job into the queue to be processed and returns immediately
+sub insert {
+    my $self = shift;
+    my $job = shift;
+
+    my $mapped_job = JOB_MAP->{$job};
+    ThrowCodeError('jobqueue_no_job_mapping', { job => $job })
+        if !$mapped_job;
+    unshift(@_, $mapped_job);
+
+    my $retval = $self->SUPER::insert(@_);
+    # XXX Need to get an error message here if insert fails, but
+    # I don't see any way to do that in TheSchwartz.
+    ThrowCodeError('jobqueue_insert_failed', { job => $job, errmsg => $@ })
+        if !$retval;
+    return $retval;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::JobQueue - Interface between Bugzilla and TheSchwartz.
+
+=head1 SYNOPSIS
+
+ use Bugzilla;
+
+ my $obj = Bugzilla->job_queue();
+ $obj->insert('send_mail', { msg => $message });
+
+=head1 DESCRIPTION
+
+Certain tasks should be done asyncronously.  The job queue system allows
+Bugzilla to use some sort of service to schedule jobs to happen asyncronously.
+
+=head2 Inserting a Job
+
+See the synopsis above for an easy to follow example on how to insert a
+job into the queue.  Give it a name and some arguments and the job will
+be sent away to be done later.
diff --git a/Bugzilla/JobQueue/Runner.pm b/Bugzilla/JobQueue/Runner.pm
new file mode 100644 (file)
index 0000000..35cfec5
--- /dev/null
@@ -0,0 +1,97 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# Mozilla Corporation. All Rights Reserved.
+#
+# Contributor(s): 
+#   Mark Smith <mark@mozilla.com>
+#   Max Kanat-Alexander <mkanat@bugzilla.org>
+
+# 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 File::Basename;
+use Pod::Usage;
+
+use Bugzilla::Constants;
+use Bugzilla::JobQueue;
+use Bugzilla::Util qw(get_text);
+BEGIN { eval "use base qw(Daemon::Generic)"; }
+
+# Required because of a bug in Daemon::Generic where it won't use the
+# "version" key from DAEMON_CONFIG.
+our $VERSION = BUGZILLA_VERSION;
+
+use constant DAEMON_CONFIG => (
+    progname => basename($0),
+    pidfile  => bz_locations()->{datadir} . '/' . basename($0) . '.pid',
+    version  => BUGZILLA_VERSION,
+);
+
+sub gd_preconfig {
+    return DAEMON_CONFIG;
+}
+
+sub gd_usage {
+    pod2usage({ -verbose => 0, -exitval => 'NOEXIT' });
+    return 0
+}
+
+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_run {
+    my $self = shift;
+
+    my $jq = Bugzilla->job_queue();
+    $jq->set_verbose($self->{debug});
+    foreach my $module (values %{ Bugzilla::JobQueue::JOB_MAP() }) {
+        eval "use $module";
+        $jq->can_do($module);
+    }
+    $jq->work;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::JobQueue::Runner - A class representing the daemon that runs the
+job queue.
+
+ 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.
index 1ffbd44e3dcd5917f69c6fcb2782db48e2ac7543..d3810b72bcae4b9d331d31c8e6899155a9793860 100644 (file)
@@ -53,10 +53,15 @@ use Email::MIME::Modifier;
 use Email::Send;
 
 sub MessageToMTA {
-    my ($msg) = (@_);
+    my ($msg, $send_now) = (@_);
     my $method = Bugzilla->params->{'mail_delivery_method'};
     return if $method eq 'None';
 
+    if (Bugzilla->params->{'use_mailer_queue'} and !$send_now) {
+        Bugzilla->job_queue->insert('send_mail', { msg => $msg });
+        return;
+    }
+
     my $email = ref($msg) ? $msg : Email::MIME->new($msg);
 
     # We add this header to uniquely identify all email that we
diff --git a/jobqueue.pl b/jobqueue.pl
new file mode 100644 (file)
index 0000000..35bd203
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/bin/perl -w
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# Mozilla Corporation. All Rights Reserved.
+#
+# Contributor(s): 
+#   Mark Smith <mark@mozilla.com>
+#   Max Kanat-Alexander <mkanat@bugzilla.org>
+
+use strict;
+use File::Basename;
+BEGIN { chdir dirname($0); }
+
+use lib qw(. lib);
+use Bugzilla;
+use Bugzilla::JobQueue::Runner;
+
+Bugzilla::JobQueue::Runner->new();
+
+=head1 NAME
+
+jobqueue.pl - Runs jobs in the background for Bugzilla.
+
+=head1 SYNOPSIS
+
+ ./jobqueue.pl [ -f ] [ -d ] { start | stop | restart | check | help | version } 
+
+   -f        Run in the foreground (don't detach)
+   -d        Output a lot of debugging information
+   start     Starts a new jobqueue daemon if there isn't one running already
+   stop             Stops a running jobqueue daemon
+   restart   Stops a running jobqueue if one is running, and then
+             starts a new one.
+   check     Report the current status of the daemon.
+   help             Display this usage info
+   version   Display the version of jobqueue.pl
+
+=head1 DESCRIPTION
+
+See L<Bugzilla::JobQueue> and L<Bugzilla::JobQueue::Runner>.
index 800fbad9b047d648f968e25f6bc42a1f93b3081f..8533257f409b0710b799d0f8fd92092744902a36 100644 (file)
   mailfrom => "The email address of the $terms.Bugzilla mail daemon.  Some email systems " _
               "require this to be a valid email address.",
 
+  use_mailer_queue => "In a large $terms.Bugzilla installation, updating"
+    _ " $terms.bugs can be very slow, because $terms.Bugzilla sends all"
+    _ " email at once. If you enable this parameter, $terms.Bugzilla will"
+    _ " queue all mail and then send it in the background. This requires"
+    _ " that you have installed certain Perl modules (as listed by"
+    _ " <code>checksetup.pl</code> for this feature), and that you are"
+    _ " running the <code>jobqueue.pl</code> daemon (otherwise your mail"
+    _ " won't get sent). This affects all mail sent by $terms.Bugzilla,"
+    _ " not just $terms.bug updates.",
+
   sendmailnow => "Sites using anything older than version 8.12 of 'sendmail' " _
                  "can achieve a significant performance increase in the " _
                  "UI -- at the cost of delaying the sending of mail -- by " _
index f85375849010dca71083cceb932461149056a756..37e052f81d1fc17b6426950c84833b55d5485ada 100644 (file)
       given.
     [% END %]
 
+  [% ELSIF error == "jobqueue_insert_failed" %]
+   [% title = "Job Queue Failure" %]
+    Inserting a <code>[% job FILTER html %]</code> job into the Job 
+    Queue failed with the following error: [% errmsg FILTER html %]
+
+  [% ELSIF error == "jobqueue_not_configured" %]
+    Using the job queue system requires that certain Perl modules
+    be installed. Run <code>checksetup.pl</code> to see what modules
+    you are missing.
+
+  [% ELSIF error == "jobqueue_no_job_mapping" %]
+    <code>Bugzilla::JobQueue</code> has not been configured to handle
+    the job "[% job FILTER html %]".  You need to add this job type
+    to the <code>JOB_MAP</code> constant in <code>Bugzilla::JobQueue</code>.
+
   [% ELSIF error == "ldap_bind_failed" %]
     Failed to bind to the LDAP server. The error message was: 
     <code>[% errstr FILTER html %]</code>
index 1a9c7220a58d2105d4fe23f6f74d33f226bbca67..1aa464c8f6373c956b47fc9f6d0da54348cad2b5 100644 (file)
       group.
     [% END %]
 
+  [% ELSIF message_tag == "job_queue_depth" %]
+    [% count FILTER html %] jobs in the queue.
+
   [% ELSIF message_tag == "keyword_created" %]
     [% title = "New Keyword Created" %]
     The keyword <em>[% name FILTER html %]</em> has been created.