10 unshift(@INC, $FindBin::Bin . '/../modules/override'); # Use our own versions of various modules (e.g. YAML).
11 push (@INC, $FindBin::Bin . '/..'); # '.' will be removed from @INC soon.
12 push (@INC, $FindBin::Bin . '/../modules/fallback'); # Only use our own versions of modules if there's no system version.
15 use CGI qw( -no_xhtml);
21 use English qw(-no_match_vars);
23 use List::MoreUtils qw(any);
24 use List::Util qw(first);
25 use POSIX qw(setuid setgid);
28 use SL::DB::AuthClient;
29 use SL::DB::BackgroundJob;
30 use SL::BackgroundJob::ALL;
32 use SL::Helper::DateTime;
33 use SL::InstanceConfiguration;
38 use SL::System::Process;
39 use SL::System::TaskServer;
45 return if !$lx_office_conf{task_server}->{debug};
46 $::lxdebug->message(LXDebug::DEBUG1(), join(' ', "task server:", @_));
50 return SL::DB::Manager::AuthClient->get_all(where => [ '!task_server_user_id' => undef ]);
53 sub initialize_kivitendo {
60 $::lxdebug = LXDebug->new;
61 $::locale = Locale->new($::lx_office_conf{system}->{language});
63 $::auth = SL::Auth->new;
67 $::auth->set_client($client->id);
69 $::form->{__ERROR_HANDLER} = sub { die @_ };
71 $::instance_conf = SL::InstanceConfiguration->new;
72 $::request = SL::Request->new(
74 layout => SL::Layout::None->new,
77 die 'cannot reach auth db' unless $::auth->session_tables_present;
79 $::auth->restore_session;
80 $::auth->create_or_refresh_session;
82 my $login = $client->task_server_user->login;
84 die "cannot find user $login" unless %::myconfig = $::auth->read_user(login => $login);
85 die "cannot find locale for user $login" unless $::locale = Locale->new($::myconfig{countrycode} || $::lx_office_conf{system}->{language});
88 sub cleanup_kivitendo {
89 eval { SL::DB->client->dbh->rollback; };
91 $::auth->save_session;
92 $::auth->expire_sessions;
101 sub clean_before_sleeping {
102 SL::DBConnect::Cache->disconnect_all_and_clear;
103 SL::DB->db_cache->clear;
105 File::Temp::cleanup();
108 sub drop_privileges {
109 my $user = $lx_office_conf{task_server}->{run_as};
113 while (my @details = getpwent()) {
114 next unless $details[0] eq $user;
115 ($uid, $gid) = @details[2, 3];
121 print "Error: Cannot drop privileges to ${user}: user does not exist\n";
126 print "Error: Cannot drop group privileges to ${user} (group ID $gid): $!\n";
131 print "Error: Cannot drop user privileges to ${user} (user ID $uid): $!\n";
136 sub notify_on_failure {
139 my $cfg = $lx_office_conf{'task_server/notify_on_failure'} || {};
141 return if any { !$cfg->{$_} } qw(send_email_to email_from email_subject email_template);
145 return debug("Template " . $cfg->{email_template} . " missing!") unless -f $cfg->{email_template};
147 my $email_to = $cfg->{send_email_to};
148 if ($email_to !~ m{\@}) {
149 my %user = $::auth->read_user(login => $email_to);
150 return debug("cannot find user for notification $email_to") unless %user;
152 $email_to = $user{email};
153 return debug("user for notification " . $user{login} . " doesn't have a valid email address") unless $email_to =~ m{\@};
156 my $template = Template->new({
163 return debug("Could not create Template instance") unless $template;
165 $params{client} = $::auth->client;
169 $template->process($cfg->{email_template}, \%params, \$body);
172 from => $cfg->{email_from},
174 subject => $cfg->{email_subject},
175 content_type => 'text/plain',
177 message => Encode::decode('utf-8', $body),
182 debug("Sending a failure notification failed with an exception: $@");
189 SL::LxOfficeConf->read($self->{configfile});
191 die "Missing section [task_server] in config file" unless $lx_office_conf{task_server};
193 if ($lx_office_conf{task_server}->{login} || $lx_office_conf{task_server}->{client}) {
195 ERROR: The keys 'login' and/or 'client' are still present in the
196 section [task_server] in the configuration file. These keys are
197 deprecated. You have to configure the clients for which to run the
198 task server in the web admin interface.
200 The task server will refuse to start until the keys have been removed from
201 the configuration file.
206 initialize_kivitendo();
208 my $dbupdater_auth = SL::DBUpgrade2->new(form => $::form, auth => 1)->parse_dbupdate_controls;
209 if ($dbupdater_auth->unapplied_upgrade_scripts($::auth->dbconnect)) {
211 The authentication database requires an upgrade. Please login to
212 kivitendo's administration interface in order to apply it. The task
213 server cannot start until the upgrade has been applied.
223 sub run_once_for_all_clients {
224 initialize_kivitendo();
226 my $clients = enabled_clients();
228 foreach my $client (@{ $clients }) {
229 debug("Running for client ID " . $client->id . " (" . $client->name . ")");
232 initialize_kivitendo($client);
234 my $jobs = SL::DB::Manager::BackgroundJob->get_all_need_to_run;
237 debug(" Executing the following jobs: " . join(' ', map { $_->package_name } @{ $jobs }));
239 debug(" No jobs to execute found");
242 foreach my $job (@{ $jobs }) {
243 # Provide fresh global variables in case legacy code modifies
245 initialize_kivitendo($client);
247 my $history = $job->run;
249 notify_on_failure(history => $history) if $history && $history->has_failed;
256 my $error = $EVAL_ERROR;
257 debug("Exception during execution: ${error}");
258 notify_on_failure(exception => $error);
267 $SIG{'ALRM'} = 'IGNORE';
269 run_once_for_all_clients();
273 clean_before_sleeping();
275 my $seconds = 60 - (localtime)[0];
278 $SIG{'ALRM'} = 'IGNORE';
279 debug("Got woken up by SIGALRM");
282 sleep($seconds < 30 ? $seconds + 60 : $seconds);
285 die $@ unless $@ eq "Alarm!\n";
290 $exe_dir = SL::System::Process->exe_dir;
291 chdir($exe_dir) || die "Cannot change directory to ${exe_dir}\n";
293 mkdir SL::System::TaskServer::PID_BASE() if !-d SL::System::TaskServer::PID_BASE();
295 my $file = first { -f } ("${exe_dir}/config/kivitendo.conf", "${exe_dir}/config/lx_office.conf", "${exe_dir}/config/kivitendo.conf.default");
297 die "No configuration file found." unless $file;
299 $file = File::Spec->abs2rel(Cwd::abs_path($file), Cwd::abs_path($exe_dir));
301 newdaemon(configfile => $file,
302 progname => 'kivitendo-background-jobs',
303 pidbase => SL::System::TaskServer::PID_BASE() . '/',