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->client->dbh->rollback; };
99 $::auth->save_session;
100 $::auth->expire_sessions;
109 sub clean_before_sleeping {
110 Form::disconnect_standard_dbh;
111 SL::DBConnect::Cache->disconnect_all_and_clear;
112 SL::DB->db_cache->clear;
114 File::Temp::cleanup();
117 sub drop_privileges {
118 my $user = $lx_office_conf{task_server}->{run_as};
122 while (my @details = getpwent()) {
123 next unless $details[0] eq $user;
124 ($uid, $gid) = @details[2, 3];
130 print "Error: Cannot drop privileges to ${user}: user does not exist\n";
135 print "Error: Cannot drop group privileges to ${user} (group ID $gid): $!\n";
140 print "Error: Cannot drop user privileges to ${user} (user ID $uid): $!\n";
145 sub notify_on_failure {
148 my $cfg = $lx_office_conf{'task_server/notify_on_failure'} || {};
150 return if any { !$cfg->{$_} } qw(send_email_to email_from email_subject email_template);
154 return debug("Template " . $cfg->{email_template} . " missing!") unless -f $cfg->{email_template};
156 my $email_to = $cfg->{send_email_to};
157 if ($email_to !~ m{\@}) {
158 my %user = $::auth->read_user(login => $email_to);
159 return debug("cannot find user for notification $email_to") unless %user;
161 $email_to = $user{email};
162 return debug("user for notification " . $user{login} . " doesn't have a valid email address") unless $email_to =~ m{\@};
165 my $template = Template->new({
172 return debug("Could not create Template instance") unless $template;
174 $params{client} = $::auth->client;
178 $template->process($cfg->{email_template}, \%params, \$body);
181 from => $cfg->{email_from},
183 subject => $cfg->{email_subject},
184 content_type => 'text/plain',
186 message => Encode::decode('utf-8', $body),
191 debug("Sending a failure notification failed with an exception: $@");
198 SL::LxOfficeConf->read($self->{configfile});
200 die "Missing section [task_server] in config file" unless $lx_office_conf{task_server};
202 if ($lx_office_conf{task_server}->{login} || $lx_office_conf{task_server}->{client}) {
204 ERROR: The keys 'login' and/or 'client' are still present in the
205 section [task_server] in the configuration file. These keys are
206 deprecated. You have to configure the clients for which to run the
207 task server in the web admin interface.
209 The task server will refuse to start until the keys have been removed from
210 the configuration file.
215 initialize_kivitendo();
217 my $dbupdater_auth = SL::DBUpgrade2->new(form => $::form, auth => 1)->parse_dbupdate_controls;
218 if ($dbupdater_auth->unapplied_upgrade_scripts($::auth->dbconnect)) {
220 The authentication database requires an upgrade. Please login to
221 kivitendo's administration interface in order to apply it. The task
222 server cannot start until the upgrade has been applied.
232 sub run_once_for_all_clients {
233 initialize_kivitendo();
235 my $clients = enabled_clients();
237 foreach my $client (@{ $clients }) {
238 debug("Running for client ID " . $client->id . " (" . $client->name . ")");
241 initialize_kivitendo($client);
243 my $jobs = SL::DB::Manager::BackgroundJob->get_all_need_to_run;
246 debug(" Executing the following jobs: " . join(' ', map { $_->package_name } @{ $jobs }));
248 debug(" No jobs to execute found");
251 foreach my $job (@{ $jobs }) {
252 # Provide fresh global variables in case legacy code modifies
254 initialize_kivitendo($client);
256 my $history = $job->run;
258 notify_on_failure(history => $history) if $history && $history->has_failed;
265 my $error = $EVAL_ERROR;
266 debug("Exception during execution: ${error}");
267 notify_on_failure(exception => $error);
276 $SIG{'ALRM'} = 'IGNORE';
278 run_once_for_all_clients();
282 clean_before_sleeping();
284 my $seconds = 60 - (localtime)[0];
287 $SIG{'ALRM'} = 'IGNORE';
288 debug("Got woken up by SIGALRM");
291 sleep($seconds < 30 ? $seconds + 60 : $seconds);
294 die $@ unless $@ eq "Alarm!\n";
301 mkdir SL::System::TaskServer::PID_BASE() if !-d SL::System::TaskServer::PID_BASE();
303 my $file = first { -f } ("${exe_dir}/config/kivitendo.conf", "${exe_dir}/config/lx_office.conf", "${exe_dir}/config/kivitendo.conf.default");
305 die "No configuration file found." unless $file;
307 $file = File::Spec->abs2rel(Cwd::abs_path($file), Cwd::abs_path($exe_dir));
309 newdaemon(configfile => $file,
310 progname => 'kivitendo-background-jobs',
311 pidbase => SL::System::TaskServer::PID_BASE() . '/',