]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 1508201 - Add framework for running background tasks
authorDylan William Hardison <dylan@hardison.net>
Tue, 27 Nov 2018 17:52:21 +0000 (12:52 -0500)
committerGitHub <noreply@github.com>
Tue, 27 Nov 2018 17:52:21 +0000 (12:52 -0500)
Bugzilla/Job/RunTask.pm [new file with mode: 0644]
Bugzilla/JobQueue.pm
Bugzilla/Task.pm [new file with mode: 0644]
Bugzilla/Types.pm

diff --git a/Bugzilla/Job/RunTask.pm b/Bugzilla/Job/RunTask.pm
new file mode 100644 (file)
index 0000000..54cc74c
--- /dev/null
@@ -0,0 +1,72 @@
+# 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.
+
+package Bugzilla::Job::RunTask;
+
+use 5.10.1;
+use strict;
+use warnings;
+
+use parent 'TheSchwartz::Worker';
+
+use constant grab_for    => 300;
+use constant max_retries => 0;
+
+use Bugzilla::Logging;
+use Module::Runtime qw(require_module);
+use Scalar::Util qw(blessed);
+use Email::MIME;
+use Bugzilla::Mailer qw(MessageToMTA);
+
+sub work {
+  my ($class, $job) = @_;
+  my $task       = $job->arg;
+  my $task_class = blessed($task) // '';
+  die "Invalid task class: $task_class"
+    unless $task_class =~ /^Bugzilla::Task::/;
+  require_module($task_class);
+
+  my $template = Bugzilla->template;
+  my $vars     = $task->run();
+  my $name     = $task->name;
+  my $html     = "";
+  my $ok       = $template->process("email/task/$name.html.tmpl", $vars, \$html);
+
+  unless ($ok) {
+    FATAL($template->error);
+    $html = "Something went run running task '$name'";
+  }
+
+  my @parts = (
+    Email::MIME->create(
+      attributes => {
+        content_type => 'text/html',
+        charset      => 'UTF-8',
+        encoding     => 'quoted-printable',
+      },
+      body_str => $html,
+    ),
+  );
+
+  my $email = Email::MIME->create(
+    header_str => [
+      From              => Bugzilla->params->{'mailfrom'},
+      To                => $task->user->email,
+      Subject           => $task->subject,
+      'X-Bugzilla-Type' => 'task',
+    ],
+    parts => [@parts],
+  );
+
+  # We're already in the jobqueue, so send right away.
+  MessageToMTA($email, 1);
+
+  $job->completed;
+}
+
+
+1;
index a78a4d0ae7d867b94e8fe9cbb9fbcf30ef61d7b7..9214d87e44dbf497b4115e19e84e18145f298ae6 100644 (file)
@@ -20,12 +20,15 @@ use IO::Async::Timer::Periodic;
 use IO::Async::Loop;
 use Future;
 use base qw(TheSchwartz);
+use Bugzilla::Types qw(Task);
+use Type::Params qw( compile Invocant );
 
 # 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',
     bug_mail  => 'Bugzilla::Job::BugMail',
+    run_task  => 'Bugzilla::Job::RunTask',
 };
 
 # Without a driver cache TheSchwartz opens a new database connection
@@ -77,6 +80,15 @@ sub bz_databases {
     return map { $self->driver_for($_) } @hashes;
 }
 
+sub run_task {
+  state $check = compile(Invocant, Task);
+  my ($self, $task) = $check->(@_);
+
+  $task->prepare;
+
+  return $self->insert(run_task => $task);
+}
+
 # inserts a job into the queue to be processed and returns immediately
 sub insert {
     my $self = shift;
diff --git a/Bugzilla/Task.pm b/Bugzilla/Task.pm
new file mode 100644 (file)
index 0000000..a5e9c9c
--- /dev/null
@@ -0,0 +1,57 @@
+# 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.
+
+package Bugzilla::Task;
+use 5.10.1;
+use Moo::Role;
+
+use Bugzilla::Constants;
+use Bugzilla::Logging;
+use Bugzilla::Types qw(User);
+use Types::Standard qw(Str);
+use Type::Utils;
+use Scalar::Util qw(blessed);
+use Mojo::Util qw(decamelize);
+use Try::Tiny;
+use Capture::Tiny qw(capture_stdout);
+
+requires 'prepare', 'run', 'subject', '_build_estimated_duration';
+
+my $Duration = class_type { class => 'DateTime::Duration' };
+
+has 'user' => (is => 'ro',   isa => User, required => 1);
+has 'name' => (is => 'lazy', isa => Str,  init_arg => undef);
+has 'estimated_duration' => (is => 'lazy', isa => $Duration, init_arg => undef);
+
+around 'run' => sub {
+  my ($original_method, $self, @args) = @_;
+  my $scope = Bugzilla->set_user($self->user, scope_guard => 1);
+  Bugzilla->error_mode(ERROR_MODE_MOJO);
+  my $result;
+  try {
+    my $stdout = capture_stdout {
+      $result = $self->$original_method(@args);
+    };
+    if ($stdout) {
+      FATAL("$self sent output to STDOUT: $stdout");
+    }
+  }
+  catch {
+    $result = {error => $_};
+  };
+  return $result;
+};
+
+sub _build_name {
+  my ($self) = @_;
+  my $class  = blessed($self);
+  my $pkg    = __PACKAGE__;
+  $class =~ s/^\Q$pkg\E:://;
+  return decamelize($class);
+}
+
+1;
index 93d699f49fa3bb90f942aea11421f718244eea69..f85335bcb680f429d3a76da9c097a8544d069b62 100644 (file)
@@ -13,7 +13,7 @@ use warnings;
 
 use Type::Library
     -base,
-    -declare => qw( Bug User Group Attachment Comment JSONBool );
+    -declare => qw( Bug User Group Attachment Comment JSONBool Task );
 use Type::Utils -all;
 use Types::Standard -types;
 
@@ -23,5 +23,6 @@ class_type Group,      { class => 'Bugzilla::Group' };
 class_type Attachment, { class => 'Bugzilla::Attachment' };
 class_type Comment,    { class => 'Bugzilla::Comment' };
 class_type JSONBool,   { class => 'JSON::PP::Boolean' };
+role_type  Task,       { role => 'Bugzilla::Task' };
 
 1;