1 package OpenSRF::System;
2 use strict; use warnings;
4 use OpenSRF::Utils::Logger qw(:level);
5 use OpenSRF::Transport::Listener;
6 use OpenSRF::Transport;
7 use OpenSRF::UnixServer;
9 use OpenSRF::Utils::LogServer;
11 use OpenSRF::EX qw/:try/;
12 use POSIX ":sys_wait_h";
13 use OpenSRF::Utils::Config;
16 =head2 Name/Description
20 To start the system: OpenSRF::System->bootstrap();
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.
27 Currently automated processes include launching the internal Unix Servers, launching the inbound
28 connections for each application, and starting the system shell.
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().
41 sub APPS { return qw( opac ); } #circ cat storage ); }
45 # ----------------------------------------------
47 $SIG{INT} = sub { instance()->killall(); };
49 $SIG{HUP} = sub{ instance()->hupall(); };
51 #$SIG{CHLD} = \&process_automation;
54 # Go ahead and set the config
58 # ----------------------------------------------
62 my $config = OpenSRF::Utils::Config->load(
63 config_file => "/pines/conf/opensrf.conf" );
65 if( ! $config ) { throw OpenSRF::EX::Config "System could not load config"; }
67 my $tran = $config->transport->implementation;
71 throw OpenSRF::EX::PANIC ("Cannot find transport implementation: $@" );
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 );
82 # ----------------------------------------------
86 # put $instance in a closure and return it for requests to new()
87 # since there should only be one System instance running
90 sub instance { return __PACKAGE__->new(); }
95 $class = ref( $class ) || $class;
97 $self->{'pid_hash'} = {};
98 bless( $self, $class );
105 # ----------------------------------------------
106 # Commands to execute at system launch
110 return "OpenSRF::UnixServer->new( '$app' )->serve()";
115 return "OpenSRF::Transport::Listener->new( '$app' )->initialize()->listen()";
118 #sub _shell { return "OpenSRF::Shell->listen()"; }
121 # ----------------------------------------------
126 my $self = __PACKAGE__->instance();
128 my $config = OpenSRF::Utils::Config->current;
130 my $apps = $config->system->apps;
131 my $server_type = $config->system->server_type;
132 $server_type ||= "basic";
134 if( $server_type eq "prefork" ) {
135 $server_type = "Net::Server::PreForkSimple";
137 $server_type = "Net::Server::Single";
140 _log( " * Server type: $server_type", INTERNAL );
142 eval "use $server_type";
145 throw OpenSRF::EX::PANIC ("Cannot set $server_type: $@" );
148 push @OpenSRF::UnixServer::ISA, $server_type;
150 _log( " * System boostrap" );
152 # Start a process group and make me the captain
157 # --- Boot the Unix servers
158 $self->launch_unix($apps);
162 # --- Boot the listeners
163 $self->launch_listener($apps);
167 # --- Start the system shell
168 #if ($config->system->shell) {
170 # use OpenSRF::Shell;
171 # $self->launch_shell() if ($config->system->shell);
175 # warn "ARRRGGG! Can't start the shell...";
179 # --- Now we wait for our brood to perish
180 _log( " * System is ready..." );
181 while( 1 ) { sleep; }
187 # ----------------------------------------------
188 # Bootstraps a single client connection.
190 sub bootstrap_client {
192 my $self = __PACKAGE__->instance();
193 my $config = OpenSRF::Utils::Config->current;
195 my $client_type = shift;
198 if( defined($client_type) and $client_type ) {
204 OpenSRF::Transport::PeerHandle->construct( $app );
208 sub bootstrap_logger {
211 OpenSRF::Utils::LogServer->serve();
216 # ----------------------------------------------
217 # Cycle through the known processes, reap the dead child
218 # and put a new child in its place. (MMWWAHAHHAHAAAA!)
220 sub process_automation {
222 my $self = __PACKAGE__->instance();
224 foreach my $pid ( keys %{$self->pid_hash} ) {
226 if( waitpid( $pid, WNOHANG ) == $pid ) {
228 my $method = $self->pid_hash->{$pid};
229 delete $self->pid_hash->{$pid};
231 my $newpid = OpenSRF::Utils::safe_fork();
232 _log( "Relaunching => $method" );
235 $self->pid_hash( $newpid, $method );
237 else { $0 = $method; eval $method; exit; }
241 $SIG{CHLD} = \&process_automation;
245 # ----------------------------------------------
246 # Launch the Unix Servers
249 my( $self, $apps ) = @_;
251 foreach my $app ( @$apps ) {
253 _log( " * Starting UnixServer for $app..." );
255 my $pid = OpenSRF::Utils::safe_fork();
257 $self->pid_hash( $pid , _unixserver( $app ) );
261 $apname =~ tr/[a-z]/[A-Z]/;
262 $0 = "Unix Server ($apname)";
263 eval _unixserver( $app );
269 # ----------------------------------------------
270 # Launch the inbound clients
272 sub launch_listener {
274 my( $self, $apps ) = @_;
276 foreach my $app ( @$apps ) {
278 _log( " * Starting Listener for $app..." );
280 my $pid = OpenSRF::Utils::safe_fork();
282 $self->pid_hash( $pid , _listener( $app ) );
286 $apname =~ tr/[a-z]/[A-Z]/;
287 $0 = "Listener ($apname)";
288 eval _listener( $app );
294 # ----------------------------------------------
301 my $pid = OpenSRF::Utils::safe_fork();
303 if( $pid ) { $self->pid_hash( $pid , _shell() ); }
306 for( my $x = 0; $x != 10; $x++ ) {
316 # ----------------------------------------------
319 my( $self, $pid, $method ) = @_;
320 $self->{'pid_hash'}->{$pid} = $method
321 if( $pid and $method );
322 return $self->{'pid_hash'};
325 # ----------------------------------------------
326 # If requested, the System can shut down.
330 $SIG{CHLD} = 'IGNORE';
331 $SIG{INT} = 'IGNORE';
332 kill( 'INT', -$$ ); #kill all in process group
337 # ----------------------------------------------
341 _log( "HUPping brood" );
342 $SIG{CHLD} = 'IGNORE';
343 $SIG{HUP} = 'IGNORE';
344 set_config(); # reload config
346 # $SIG{CHLD} = \&process_automation;
347 $SIG{HUP} = sub{ instance()->hupall(); };
351 # ----------------------------------------------
352 # Log to debug, and stdout
356 OpenSRF::Utils::Logger->debug( $string );
357 print $string . "\n";
360 # ----------------------------------------------
363 select( undef, undef, undef, 0.3 );