]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/perlmods/OpenSRF/System.pm
making to work in new environment, added 'system_client' login for system
[OpenSRF.git] / src / perlmods / OpenSRF / System.pm
1 package OpenSRF::System;
2 use strict; use warnings;
3 use base 'OpenSRF';
4 use OpenSRF::Utils::Logger qw(:level);
5 use OpenSRF::Transport::Listener;
6 use OpenSRF::Transport;
7 use OpenSRF::UnixServer;
8 use OpenSRF::Utils;
9 use OpenSRF::Utils::LogServer;
10 use OpenSRF::DOM;
11 use OpenSRF::EX qw/:try/;
12 use POSIX ":sys_wait_h";
13 use OpenSRF::Utils::Config; 
14 use strict;
15
16 =head2 Name/Description
17
18 OpenSRF::System
19
20 To start the system: OpenSRF::System->bootstrap();
21
22 Simple system process management and automation.  After instantiating the class, simply call
23 bootstrap() to launch the system.  Each launched process is stored as a process-id/method-name
24 pair in a local hash.  When we receive a SIG{CHILD}, we loop through this hash and relaunch
25 any child processes that may have terminated.  
26
27 Currently automated processes include launching the internal Unix Servers, launching the inbound 
28 connections for each application, and starting the system shell.
29
30
31 Note: There should be only one instance of this class
32 alive at any given time.  It is designed as a globel process handler and, hence, will cause much
33 oddness if you call the bootstrap() method twice or attempt to create two of these by trickery.
34 There is a single instance of the class created on the first call to new().  This same instance is 
35 returned on subsequent calls to new().
36
37 =cut
38
39 $| = 1;
40
41 sub APPS { return qw( opac ); } #circ cat storage ); }
42
43 sub DESTROY {}
44
45 # ----------------------------------------------
46
47 $SIG{INT} = sub { instance()->killall(); };
48
49 $SIG{HUP} = sub{ instance()->hupall(); };
50
51 #$SIG{CHLD} = \&process_automation;
52
53
54 # Go ahead and set the config
55
56 set_config();
57
58 # ----------------------------------------------
59 # Set config options
60 sub set_config {
61
62         my $config = OpenSRF::Utils::Config->load( 
63                 config_file => "/pines/conf/opensrf.conf" );
64
65         if( ! $config ) { throw OpenSRF::EX::Config "System could not load config"; }
66
67         my $tran = $config->transport->implementation;
68
69         eval "use $tran;";
70         if( $@ ) {
71                 throw OpenSRF::EX::PANIC ("Cannot find transport implementation: $@" );
72         }
73
74         OpenSRF::Transport->message_envelope( $tran->get_msg_envelope );
75         OpenSRF::Transport::PeerHandle->set_peer_client( $tran->get_peer_client );
76         OpenSRF::Transport::Listener->set_listener( $tran->get_listener );
77
78
79 }
80
81
82 # ----------------------------------------------
83
84
85         # --- 
86         # put $instance in a closure and return it for requests to new()
87         # since there should only be one System instance running
88         # ----- 
89         my $instance;
90         sub instance { return __PACKAGE__->new(); }
91         sub new {
92                 my( $class ) = @_;
93
94                 if( ! $instance ) {
95                         $class = ref( $class ) || $class;
96                         my $self = {};
97                         $self->{'pid_hash'} = {};
98                         bless( $self, $class );
99                         $instance = $self;
100                 }
101                 return $instance;
102         }
103 }
104
105 # ----------------------------------------------
106 # Commands to execute at system launch
107
108 sub _unixserver {
109         my( $app ) = @_;
110         return "OpenSRF::UnixServer->new( '$app' )->serve()";
111 }
112
113 sub _listener {
114         my( $app ) = @_;
115         return "OpenSRF::Transport::Listener->new( '$app' )->initialize()->listen()";
116 }
117
118 #sub _shell { return "OpenSRF::Shell->listen()"; }
119
120
121 # ----------------------------------------------
122 # Boot up the system
123
124 sub bootstrap {
125
126         my $self = __PACKAGE__->instance();
127
128         my $config = OpenSRF::Utils::Config->current;
129
130         my $apps = $config->system->apps;
131         my $server_type = $config->system->server_type;
132         $server_type ||= "basic";
133
134         if(  $server_type eq "prefork" ) { 
135                 $server_type = "Net::Server::PreForkSimple"; 
136         } else { 
137                 $server_type = "Net::Server::Single"; 
138         }
139
140         _log( " * Server type: $server_type", INTERNAL );
141
142         eval "use $server_type";
143
144         if( $@ ) {
145                 throw OpenSRF::EX::PANIC ("Cannot set $server_type: $@" );
146         }
147
148         push @OpenSRF::UnixServer::ISA, $server_type;
149
150         _log( " * System boostrap" );
151
152         # Start a process group and make me the captain
153         setpgrp( 0, 0 ); 
154
155         $0 = "System";
156         
157         # --- Boot the Unix servers
158         $self->launch_unix($apps);
159
160         _sleep();
161
162         # --- Boot the listeners
163         $self->launch_listener($apps);
164
165         _sleep();
166
167         # --- Start the system shell
168 #if ($config->system->shell) {
169 #               eval " 
170 #                       use OpenSRF::Shell;
171 #                       $self->launch_shell() if ($config->system->shell);
172 #               ";
173 #
174 #               if ($@) {
175 #                       warn "ARRRGGG! Can't start the shell...";
176 #               }
177 #       }
178
179         # --- Now we wait for our brood to perish
180         _log( " * System is ready..." );
181         while( 1 ) { sleep; }
182         exit;
183 }
184
185
186
187 # ----------------------------------------------
188 # Bootstraps a single client connection.  
189
190 sub bootstrap_client {
191
192         my $self = __PACKAGE__->instance();
193         my $config = OpenSRF::Utils::Config->current;
194
195         my $client_type = shift;
196         my $app;
197
198         if( defined($client_type) and $client_type ) {
199                 $app = $client_type;
200         } else {
201                 $app = "client";
202         }
203
204         OpenSRF::Transport::PeerHandle->construct( $app );
205
206 }
207
208 sub bootstrap_logger {
209
210         $0 = "Log Server";
211         OpenSRF::Utils::LogServer->serve();
212
213 }
214
215
216 # ----------------------------------------------
217 # Cycle through the known processes, reap the dead child 
218 # and put a new child in its place. (MMWWAHAHHAHAAAA!)
219
220 sub process_automation {
221
222         my $self = __PACKAGE__->instance();
223
224         foreach my $pid ( keys %{$self->pid_hash} ) {
225
226                 if( waitpid( $pid, WNOHANG ) == $pid ) {
227
228                         my $method = $self->pid_hash->{$pid};
229                         delete $self->pid_hash->{$pid};
230
231                         my $newpid =  OpenSRF::Utils::safe_fork();
232                         _log( "Relaunching => $method" );
233
234                         if( $newpid ) {
235                                 $self->pid_hash( $newpid, $method );
236                         }
237                         else { $0 = $method; eval $method; exit; }
238                 }
239         }
240
241         $SIG{CHLD} = \&process_automation;
242 }
243
244
245 # ----------------------------------------------
246 # Launch the Unix Servers
247
248 sub launch_unix {
249         my( $self, $apps ) = @_;
250
251         foreach my $app ( @$apps ) {
252
253                 _log( " * Starting UnixServer for $app..." );
254
255                 my $pid = OpenSRF::Utils::safe_fork();
256                 if( $pid ) {
257                         $self->pid_hash( $pid , _unixserver( $app ) );
258                 }
259                 else {
260                         my $apname = $app;
261                         $apname =~ tr/[a-z]/[A-Z]/;
262                         $0 = "Unix Server ($apname)";
263                         eval _unixserver( $app );
264                         exit;
265                 }
266         }
267 }
268
269 # ----------------------------------------------
270 # Launch the inbound clients
271
272 sub launch_listener {
273
274         my( $self, $apps ) = @_;
275
276         foreach my $app ( @$apps ) {
277
278                 _log( " * Starting Listener for $app..." );
279
280                 my $pid = OpenSRF::Utils::safe_fork();
281                 if ( $pid ) {
282                         $self->pid_hash( $pid , _listener( $app ) );
283                 }
284                 else {
285                         my $apname = $app;
286                         $apname =~ tr/[a-z]/[A-Z]/;
287                         $0 = "Listener ($apname)";
288                         eval _listener( $app );
289                         exit;
290                 }
291         }
292 }
293
294 # ----------------------------------------------
295
296 =head comment
297 sub launch_shell {
298
299         my $self = shift;
300
301         my $pid = OpenSRF::Utils::safe_fork();
302
303         if( $pid ) { $self->pid_hash( $pid , _shell() ); }
304         else {
305                 $0 = "System Shell";
306                 for( my $x = 0; $x != 10; $x++ ) {
307                         eval _shell();
308                         if( ! $@ ) { last; }
309                 }
310                 exit;
311         }
312 }
313 =cut
314
315
316 # ----------------------------------------------
317
318 sub pid_hash {
319         my( $self, $pid, $method ) = @_;
320         $self->{'pid_hash'}->{$pid} = $method
321                 if( $pid and $method );
322         return $self->{'pid_hash'};
323 }
324
325 # ----------------------------------------------
326 # If requested, the System can shut down.
327
328 sub killall {
329
330         $SIG{CHLD} = 'IGNORE';
331         $SIG{INT} = 'IGNORE';
332         kill( 'INT', -$$ ); #kill all in process group
333         exit;
334
335 }
336
337 # ----------------------------------------------
338 # Handle $SIG{HUP}
339 sub hupall {
340
341         _log( "HUPping brood" );
342         $SIG{CHLD} = 'IGNORE';
343         $SIG{HUP} = 'IGNORE';
344         set_config(); # reload config
345         kill( 'HUP', -$$ );
346 #       $SIG{CHLD} = \&process_automation;
347         $SIG{HUP} = sub{ instance()->hupall(); };
348 }
349
350
351 # ----------------------------------------------
352 # Log to debug, and stdout
353
354 sub _log {
355         my $string = shift;
356         OpenSRF::Utils::Logger->debug( $string );
357         print $string . "\n";
358 }
359
360 # ----------------------------------------------
361
362 sub _sleep {
363         select( undef, undef, undef, 0.3 );
364 }
365
366 1;
367
368