#!/usr/bin/perl
-
-use List::MoreUtils qw(any);
-
use strict;
my $exe_dir;
BEGIN {
use FindBin;
- use lib "$FindBin::Bin/..";
-
- use SL::System::Process;
- $exe_dir = SL::System::Process::exe_dir;
- unshift @INC, "${exe_dir}/modules/override"; # Use our own versions of various modules (e.g. YAML).
- push @INC, "${exe_dir}/modules/fallback"; # Only use our own versions of modules if there's no system version.
- unshift @INC, $exe_dir;
-
- chdir($exe_dir) || die "Cannot change directory to ${exe_dir}\n";
+ unshift(@INC, $FindBin::Bin . '/../modules/override'); # Use our own versions of various modules (e.g. YAML).
+ push (@INC, $FindBin::Bin . '/..'); # '.' will be removed from @INC soon.
}
use CGI qw( -no_xhtml);
use Daemon::Generic;
use Data::Dumper;
use DateTime;
-use Encode qw();
use English qw(-no_match_vars);
use File::Spec;
+use List::MoreUtils qw(any);
use List::Util qw(first);
-use POSIX qw(setuid setgid);
+use POSIX qw(setlocale setuid setgid);
use SL::Auth;
use SL::DBUpgrade2;
use SL::DB::AuthClient;
use SL::DB::BackgroundJob;
-use SL::BackgroundJob::ALL;
+use SL::System::Process;
use SL::Form;
use SL::Helper::DateTime;
use SL::InstanceConfiguration;
use SL::LxOfficeConf;
use SL::Locale;
use SL::Mailer;
+use SL::System::Process;
use SL::System::TaskServer;
use Template;
our %lx_office_conf;
+our $run_single_job;
sub debug {
return if !$lx_office_conf{task_server}->{debug};
package main;
- Form::disconnect_standard_dbh;
$::lxdebug = LXDebug->new;
$::locale = Locale->new($::lx_office_conf{system}->{language});
$::form = Form->new;
}
sub cleanup_kivitendo {
- eval { SL::DB::Auth->new->db->dbh->rollback; };
- eval { SL::DB::BackgroundJob->new->db->dbh->rollback; };
+ eval { SL::DB->client->dbh->rollback; };
$::auth->save_session;
$::auth->expire_sessions;
}
sub clean_before_sleeping {
- Form::disconnect_standard_dbh;
SL::DBConnect::Cache->disconnect_all_and_clear;
SL::DB->db_cache->clear;
+
+ File::Temp::cleanup();
}
sub drop_privileges {
EVAL_PERL => 0,
ABSOLUTE => 1,
CACHE_SIZE => 0,
+ ENCODING => 'utf8',
});
return debug("Could not create Template instance") unless $template;
subject => $cfg->{email_subject},
content_type => 'text/plain',
charset => 'utf-8',
- message => Encode::decode('utf-8', $body),
+ message => $body,
)->send;
1;
sub gd_preconfig {
my $self = shift;
+ # Initialize character type locale to be UTF-8 instead of C:
+ foreach my $locale (qw(de_DE.UTF-8 en_US.UTF-8)) {
+ last if setlocale('LC_CTYPE', $locale);
+ }
+
SL::LxOfficeConf->read($self->{configfile});
die "Missing section [task_server] in config file" unless $lx_office_conf{task_server};
return ();
}
+sub run_single_job_for_all_clients {
+ initialize_kivitendo();
+
+ my $clients = enabled_clients();
+
+ foreach my $client (@{ $clients }) {
+ debug("Running single job ID $run_single_job for client ID " . $client->id . " (" . $client->name . ")");
+
+ my $ok = eval {
+ initialize_kivitendo($client);
+
+ my $job = SL::DB::Manager::BackgroundJob->find_by(id => $run_single_job);
+
+ if ($job) {
+ debug(" Executing the following job: " . $job->package_name);
+ } else {
+ debug(" No jobs to execute found");
+ next;
+ }
+
+ # Provide fresh global variables in case legacy code modifies
+ # them somehow.
+ initialize_kivitendo($client);
+
+ my $history = $job->run;
+
+ debug(" Executed job " . $job->package_name .
+ "; result: " . (!$history ? "no return value" : $history->has_failed ? "failed" : "succeeded") .
+ ($history && $history->has_failed ? "; error: " . $history->error_col : ""));
+
+ notify_on_failure(history => $history) if $history && $history->has_failed;
+
+ 1;
+ };
+
+ if (!$ok) {
+ my $error = $EVAL_ERROR;
+ $::lxdebug->message(LXDebug::WARN(), "Exception during execution: ${error}");
+ notify_on_failure(exception => $error);
+ }
+
+ cleanup_kivitendo();
+ }
+}
+
sub run_once_for_all_clients {
initialize_kivitendo();
my $history = $job->run;
+ debug(" Executed job " . $job->package_name .
+ "; result: " . (!$history ? "no return value" : $history->has_failed ? "failed" : "succeeded") .
+ ($history && $history->has_failed ? "; error: " . $history->error_col : ""));
+
notify_on_failure(history => $history) if $history && $history->has_failed;
}
if (!$ok) {
my $error = $EVAL_ERROR;
- debug("Exception during execution: ${error}");
+ $::lxdebug->message(LXDebug::WARN(), "Exception during execution: ${error}");
notify_on_failure(exception => $error);
}
}
sub gd_run {
+ if ($run_single_job) {
+ 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';
+
run_once_for_all_clients();
debug("Sleeping");
clean_before_sleeping();
+ if (SL::System::Process::memory_usage_is_too_high()) {
+ debug("Memory usage too high - exiting.");
+ return;
+ }
+
my $seconds = 60 - (localtime)[0];
if (!eval {
- local $SIG{'ALRM'} = sub {
+ $SIG{'ALRM'} = sub {
+ $SIG{'ALRM'} = 'IGNORE';
debug("Got woken up by SIGALRM");
die "Alarm!\n"
};
}
}
-sub end_of_request {
- $main::lxdebug->show_backtrace();
- die <<EOF;
-Job called ::end_of_request()!
-
-This usually indicates success but should not be used by background jobs. A
-backtrace has been logged. Please tell the job author to have a look at it.
-EOF
-
+sub gd_flags_more {
+ return (
+ '--run-job=<id>' => 'Run the single job with the database ID <id> no matter if it is active or when its next execution is supposed to be; the daemon will exit afterwards',
+ );
}
-chdir $exe_dir;
+$exe_dir = SL::System::Process->exe_dir;
+chdir($exe_dir) || die "Cannot change directory to ${exe_dir}\n";
mkdir SL::System::TaskServer::PID_BASE() if !-d SL::System::TaskServer::PID_BASE();
newdaemon(configfile => $file,
progname => 'kivitendo-background-jobs',
pidbase => SL::System::TaskServer::PID_BASE() . '/',
+ options => {
+ 'run-job=i' => \$run_single_job,
+ },
);
1;