Task-Server auf unterschiedlichen Maschinen laufen lassen können
authorMoritz Bunkus <m.bunkus@linet-services.de>
Fri, 23 Aug 2019 09:17:39 +0000 (11:17 +0200)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Fri, 23 Aug 2019 09:17:39 +0000 (11:17 +0200)
Jede Task-Server-Instanz und jeder Hintergrundjob haben nun ein neues
Attribute »node_id«. Darüber kann gesteuert werden, dass bestimmte
Jobs nur von einer bestimmten Instanz ausgeführt werden.

Die »node_id« eines neu angelegten Jobs ist standardmäßig leer. Das
bedeutet, dass ein Job von einer beliebigen Task-Server-Instanz
ausgeführt werden kann.

Die »node_id« eines Task-Servers ist standardmäßig der Hostname (siehe
ausgabe von »perl -MSys::Hostname -le 'print hostname()'«), kann aber
in der Konfigurationsdatei überschrieben werden (»[task_server]« →
»node_id«).

Zusätzlich gibt es den Konfigurationsparameter »[task_server]« →
»only_run_tasks_for_this_node«. Ist dieser Parameter gesetzt, so führt
der Task-Server nur diejenigen Jobs aus, deren »node_id«-Feld mit der
»node_id« der Task-Server-Instanz übereinstimmt. Andernfalls werden
auch diejenigen Jobs ausgeführt, deren »node_id«-Feld leer ist.

Achtung: es findet momentan keinerlei Locking statt. Das bedeutet,
dass es für jede Datenbank nur eine Task-Server-Instanz geben darf,
bei der »only_run_tasks_for_this_node« nicht gesetzt ist. Für
Load-Balancing eignet sich das also bisher noch nicht.

SL/BackgroundJob/Test.pm
SL/DB/Manager/BackgroundJob.pm
SL/DB/MetaSetup/BackgroundJob.pm
SL/System/TaskServer.pm
config/kivitendo.conf.default
scripts/task_server.pl
sql/Pg-upgrade2/add_node_id_to_background_jobs.sql [new file with mode: 0644]

index c8c76db..a70b7a3 100644 (file)
@@ -4,11 +4,13 @@ use strict;
 
 use parent qw(SL::BackgroundJob::Base);
 
+use SL::System::TaskServer;
+
 sub run {
   my ($self, $db_obj) = @_;
   my $data            = $db_obj->data_as_hash;
 
-  $::lxdebug->message(0, "Test job is being executed.");
+  $::lxdebug->message(0, "Test job ID " . $db_obj->id . " is being executed on node " . SL::System::TaskServer::node_id() . ".");
 
   die "Oh cruel world: " . $data->{exception} if $data->{exception};
 
index 6212f94..8b2e99a 100644 (file)
@@ -8,6 +8,8 @@ use base qw(SL::DB::Helper::Manager);
 use SL::DB::Helper::Paginated;
 use SL::DB::Helper::Sorted;
 
+use SL::System::TaskServer;
+
 sub object_class { 'SL::DB::BackgroundJob' }
 
 __PACKAGE__->make_manager_methods;
@@ -36,8 +38,21 @@ sub get_all_need_to_run {
                                                  cron_spec   => '',
                                                  next_run_at => undef,
                                                  next_run_at => { le => $now } ] ]);
-
-  return $class->get_all(query => [ or => [ @interval_args, @once_args ] ]);
+  my @node_filter;
+
+  my $node_id = SL::System::TaskServer->node_id;
+  if ($::lx_office_conf{task_server}->{only_run_tasks_for_this_node}) {
+    @node_filter = (node_id => $node_id);
+  } else {
+    @node_filter = (
+      or => [
+        node_id => undef,
+        node_id => '',
+        node_id => $node_id,
+      ]);
+  }
+
+  return $class->get_all(query => [ or => [ @interval_args, @once_args ], @node_filter ]);
 }
 
 1;
index 5b674aa..ce2ed7e 100644 (file)
@@ -15,6 +15,7 @@ __PACKAGE__->meta->columns(
   id           => { type => 'serial', not_null => 1 },
   last_run_at  => { type => 'timestamp' },
   next_run_at  => { type => 'timestamp' },
+  node_id      => { type => 'text' },
   package_name => { type => 'varchar', length => 255 },
   type         => { type => 'varchar', length => 255 },
 );
index e410e73..a37cd03 100644 (file)
@@ -11,6 +11,7 @@ use Rose::Object::MakeMethods::Generic (
 use File::Slurp;
 use File::Spec::Functions qw(:ALL);
 use File::Temp;
+use Sys::Hostname ();
 
 use SL::System::Process;
 
@@ -22,6 +23,8 @@ use constant {
 
 use constant PID_BASE => "users/pid";
 
+my $node_id;
+
 sub status {
   my ($self) = @_;
 
@@ -63,6 +66,14 @@ sub wake_up {
   return kill('ALRM', $pid) ? 1 : undef;
 }
 
+sub node_id {
+  return $node_id if $node_id;
+
+  $node_id = ($::lx_office_conf{task_server} // {})->{node_id} || Sys::Hostname::hostname();
+
+  return $node_id;
+}
+
 #
 # private methods
 #
index 0715dc0..0d88cfc 100644 (file)
@@ -189,6 +189,11 @@ openofficeorg_daemon_port = 2002
 debug = 0
 # Chose a system user the daemon should run under when started as root.
 run_as =
+# Task servers can run on multiple machines. Each needs its own unique
+# ID. If unset, it defaults to the host name. All but one task server
+# must have 'only_run_tasks_for_this_node' set to 1.
+node_id =
+only_run_tasks_for_this_node = 0
 
 [task_server/notify_on_failure]
 # If you want email notifications for failed jobs then set this to a
index c9494c8..3d28149 100755 (executable)
@@ -322,6 +322,7 @@ sub gd_run {
     run_single_job_for_all_clients();
     return;
   }
+  $::lxdebug->message(LXDebug::INFO(), "The task server for node " . SL::System::TaskServer::node_id() . " is up and running.");
 
   while (1) {
     $SIG{'ALRM'} = 'IGNORE';
diff --git a/sql/Pg-upgrade2/add_node_id_to_background_jobs.sql b/sql/Pg-upgrade2/add_node_id_to_background_jobs.sql
new file mode 100644 (file)
index 0000000..6fac50e
--- /dev/null
@@ -0,0 +1,5 @@
+-- @tag: add_node_id_to_background_jobs
+-- @description: Spalte 'node_id' in 'background_jobs'
+-- @depends: release_3_5_4
+ALTER TABLE background_jobs
+ADD COLUMN node_id TEXT;