4 use List::MoreUtils qw(any);
12 use lib "$FindBin::Bin/..";
14 use SL::System::Process;
15 $exe_dir = SL::System::Process::exe_dir;
17 unshift @INC, "${exe_dir}/modules/override"; # Use our own versions of various modules (e.g. YAML).
18 push @INC, "${exe_dir}/modules/fallback"; # Only use our own versions of modules if there's no system version.
19 unshift @INC, $exe_dir;
21 chdir($exe_dir) || die "Cannot change directory to ${exe_dir}\n";
24 use CGI qw( -no_xhtml);
30 use English qw(-no_match_vars);
32 use List::Util qw(first);
33 use POSIX qw(setuid setgid);
36 use SL::DB::AuthClient;
37 use SL::DB::BackgroundJob;
38 use SL::BackgroundJob::ALL;
40 use SL::Helper::DateTime;
41 use SL::InstanceConfiguration;
46 use SL::System::TaskServer;
52 return if !$lx_office_conf{task_server}->{debug};
53 $::lxdebug->message(LXDebug::DEBUG1(), join(' ', "task server:", @_));
57 return SL::DB::Manager::AuthClient->get_all(where => [ '!task_server_user_id' => undef ]);
60 sub initialize_kivitendo {
67 Form::disconnect_standard_dbh;
68 $::lxdebug = LXDebug->new;
69 $::locale = Locale->new($::lx_office_conf{system}->{language});
71 $::auth = SL::Auth->new;
75 $::auth->set_client($client->id);
77 $::form->{__ERROR_HANDLER} = sub { die @_ };
79 $::instance_conf = SL::InstanceConfiguration->new;
80 $::request = SL::Request->new(
82 layout => SL::Layout::None->new,
85 die 'cannot reach auth db' unless $::auth->session_tables_present;
87 $::auth->restore_session;
88 $::auth->create_or_refresh_session;
90 my $login = $client->task_server_user->login;
92 die "cannot find user $login" unless %::myconfig = $::auth->read_user(login => $login);
93 die "cannot find locale for user $login" unless $::locale = Locale->new($::myconfig{countrycode} || $::lx_office_conf{system}->{language});
96 sub cleanup_kivitendo {
97 eval { SL::DB::Auth->new->db->dbh->rollback; };
98 eval { SL::DB::BackgroundJob->new->db->dbh->rollback; };
100 $::auth->save_session;
101 $::auth->expire_sessions;
110 sub clean_before_sleeping {
111 Form::disconnect_standard_dbh;
112 SL::DBConnect::Cache->disconnect_all_and_clear;
113 SL::DB->db_cache->clear;
115 File::Temp::cleanup();
118 sub drop_privileges {
119 my $user = $lx_office_conf{task_server}->{run_as};
123 while (my @details = getpwent()) {
124 next unless $details[0] eq $user;
125 ($uid, $gid) = @details[2, 3];
131 print "Error: Cannot drop privileges to ${user}: user does not exist\n";
136 print "Error: Cannot drop group privileges to ${user} (group ID $gid): $!\n";
141 print "Error: Cannot drop user privileges to ${user} (user ID $uid): $!\n";
146 sub notify_on_failure {
149 my $cfg = $lx_office_conf{'task_server/notify_on_failure'} || {};
151 return if any { !$cfg->{$_} } qw(send_email_to email_from email_subject email_template);
155 return debug("Template " . $cfg->{email_template} . " missing!") unless -f $cfg->{email_template};
157 my $email_to = $cfg->{send_email_to};
158 if ($email_to !~ m{\@}) {
159 my %user = $::auth->read_user(login => $email_to);
160 return debug("cannot find user for notification $email_to") unless %user;
162 $email_to = $user{email};
163 return debug("user for notification " . $user{login} . " doesn't have a valid email address") unless $email_to =~ m{\@};
166 my $template = Template->new({
173 return debug("Could not create Template instance") unless $template;
175 $params{client} = $::auth->client;
179 $template->process($cfg->{email_template}, \%params, \$body);
182 from => $cfg->{email_from},
184 subject => $cfg->{email_subject},
185 content_type => 'text/plain',
187 message => Encode::decode('utf-8', $body),
192 debug("Sending a failure notification failed with an exception: $@");
199 SL::LxOfficeConf->read($self->{configfile});
201 die "Missing section [task_server] in config file" unless $lx_office_conf{task_server};
203 if ($lx_office_conf{task_server}->{login} || $lx_office_conf{task_server}->{client}) {
205 ERROR: The keys 'login' and/or 'client' are still present in the
206 section [task_server] in the configuration file. These keys are
207 deprecated. You have to configure the clients for which to run the
208 task server in the web admin interface.
210 The task server will refuse to start until the keys have been removed from
211 the configuration file.
216 initialize_kivitendo();
218 my $dbupdater_auth = SL::DBUpgrade2->new(form => $::form, auth => 1)->parse_dbupdate_controls;
219 if ($dbupdater_auth->unapplied_upgrade_scripts($::auth->dbconnect)) {
221 The authentication database requires an upgrade. Please login to
222 kivitendo's administration interface in order to apply it. The task
223 server cannot start until the upgrade has been applied.
233 sub run_once_for_all_clients {
234 initialize_kivitendo();
236 my $clients = enabled_clients();
238 foreach my $client (@{ $clients }) {
239 debug("Running for client ID " . $client->id . " (" . $client->name . ")");
242 initialize_kivitendo($client);
244 my $jobs = SL::DB::Manager::BackgroundJob->get_all_need_to_run;
247 debug(" Executing the following jobs: " . join(' ', map { $_->package_name } @{ $jobs }));
249 debug(" No jobs to execute found");
252 foreach my $job (@{ $jobs }) {
253 # Provide fresh global variables in case legacy code modifies
255 initialize_kivitendo($client);
257 my $history = $job->run;
259 notify_on_failure(history => $history) if $history && $history->has_failed;
266 my $error = $EVAL_ERROR;
267 debug("Exception during execution: ${error}");
268 notify_on_failure(exception => $error);
277 $SIG{'ALRM'} = 'IGNORE';
279 run_once_for_all_clients();
283 clean_before_sleeping();
285 my $seconds = 60 - (localtime)[0];
288 $SIG{'ALRM'} = 'IGNORE';
289 debug("Got woken up by SIGALRM");
292 sleep($seconds < 30 ? $seconds + 60 : $seconds);
295 die $@ unless $@ eq "Alarm!\n";
302 mkdir SL::System::TaskServer::PID_BASE() if !-d SL::System::TaskServer::PID_BASE();
304 my $file = first { -f } ("${exe_dir}/config/kivitendo.conf", "${exe_dir}/config/lx_office.conf", "${exe_dir}/config/kivitendo.conf.default");
306 die "No configuration file found." unless $file;
308 $file = File::Spec->abs2rel(Cwd::abs_path($file), Cwd::abs_path($exe_dir));
310 newdaemon(configfile => $file,
311 progname => 'kivitendo-background-jobs',
312 pidbase => SL::System::TaskServer::PID_BASE() . '/',