df67523ec08eccc8c39c4b9f0123d7404f1f8053
[kivitendo-erp.git] / SL / System / TaskServer.pm
1 package SL::System::TaskServer;
2
3 use strict;
4
5 use parent qw(Rose::Object);
6
7 use Rose::Object::MakeMethods::Generic (
8   scalar => [ qw(last_command_output) ],
9 );
10
11 use File::Slurp;
12 use File::Spec::Functions qw(:ALL);
13 use File::Temp qw(tempfile);
14
15 use SL::System::Process;
16
17 use constant {
18   OK           =>  0,
19   ERR_PID_FILE => -1,
20   ERR_PROCESS  => -2,
21 };
22
23 sub status {
24   my ($self) = @_;
25
26   my $pid = $self->_read_pid;
27   return ERR_PID_FILE unless $pid;
28
29   return kill(0, $pid) ? OK : ERR_PROCESS;
30 }
31
32 sub is_running {
33   my ($self) = @_;
34
35   return $self->status == OK;
36 }
37
38 sub start {
39   my ($self) = @_;
40
41   return $self->_run_script_command('start');
42 }
43
44 sub stop {
45   my ($self) = @_;
46
47   return $self->_run_script_command('stop');
48 }
49
50 sub wake_up {
51   my ($self) = @_;
52
53   my $pid = $self->_read_pid;
54   return undef unless $pid;
55   return kill('ALRM', $pid) ? 1 : undef;
56 }
57
58 #
59 # private methods
60 #
61
62 sub _read_pid {
63   my ($self) = @_;
64
65   my $exe_dir = SL::System::Process->exe_dir;
66
67   foreach my $conf (qw(kivitendo.conf lx_office.conf kivitendo.conf.default)) {
68     my $pid_file_name = join '.', splitdir($exe_dir), "config.${conf}.pid";
69     my $pid_file_path = catfile(catdir($exe_dir, 'users', 'pid'), $pid_file_name);
70
71     return join('', read_file($pid_file_path)) * 1 if -f $pid_file_path;
72   }
73 }
74
75 sub _run_script_command {
76   my ($self, $command) = @_;
77
78   my ($fh, $file_name) = tempfile();
79   my $exe              = catfile(catdir(SL::System::Process->exe_dir, 'scripts'), 'task_server.pl');
80
81   system "${exe} ${command} >> ${file_name} 2>&1";
82
83   $fh->close;
84
85   $self->last_command_output(read_file($file_name));
86
87   return $? == 0 ? 1 : undef;
88 }
89
90 1;
91 __END__
92
93 =pod
94
95 =encoding utf8
96
97 =head1 NAME
98
99 SL::System::TaskServer - programmatic interface to the external task server component
100
101 =head1 SYNOPSIS
102
103   # Create interface
104   my $task_server = SL->TaskServer->new;
105
106   # Start the server if it is not running
107   if (!$task_server->is_running) {
108     $task_server->start;
109   }
110
111   # Stop it if it is running
112   if ($task_server->is_running) {
113     $task_server->stop;
114   }
115
116 =head1 FUNCTIONS
117
118 =over 4
119
120 =item C<is_running>
121
122 Returns C<trueish> if the server is running. This is done by using
123 Perl's C<kill> function with a "signal" of C<0> for the process ID
124 which in turn is read from the daemon's PID file.
125
126 If the PID file is not found or if C<kill> returns a non-successful
127 value then a C<falsish> value is returned.
128
129 =item C<last_command_output>
130
131 Returns the output of the last C<system> command executed, e.g. from a
132 call to L<start> or L<stop>.
133
134 =item C<start>
135
136 Starts the task server. Does not check whether or not it is running,
137 neither before not after trying to start it.
138
139 Returns C<1> if the system command C<./scripts/task_server.pl start>
140 exits with an exit code of C<0> and C<undef> otherwise.
141
142 The command's output can be queried with L<last_command_output>.
143
144 =item C<status>
145
146 Queries the task server status. Returns one of these values:
147
148 =over 4
149
150 =item *
151
152 C<OK> or C<0>: the task server is running and signals can be sent to
153 it.
154
155 =item *
156
157 C<ERR_PID_FILE> or C<-1>: the PID file could not be found or read
158
159 =item *
160
161 C<ERR_PROCESS> or C<-2>: the PID file could was found and read, but
162 it's not possible to send signals to the process, e.g. because it is
163 not running or owned by a different user ID.
164
165 =back
166
167 =item C<stop>
168
169 Stops the task server. Does not check whether or not it is running,
170 neither before not after trying to start it.
171
172 Returns C<1> if the system command C<./scripts/task_server.pl stop>
173 exits with an exit code of C<0> and C<undef> otherwise.
174
175 The command's output can be queried with L<last_command_output>.
176
177 =item C<wake_up>
178
179 Sends a signal to the task server process causing it to wake up and
180 process its job queue immediately.
181
182 Returns C<1> if the signal could be sent and C<undef> otherwise.
183
184 =back
185
186 =head1 BUGS
187
188 Nothing here yet.
189
190 =head1 AUTHOR
191
192 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
193
194 =cut