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 warn "Setting config " . $config->transport->implementation ."\n";
67 if( ! $config ) { throw OpenSRF::EX::Config "System could not load config"; }
69 my $tran = $config->transport->implementation;
73 throw OpenSRF::EX::PANIC ("Cannot find transport implementation: $@" );
76 OpenSRF::Transport->message_envelope( $tran->get_msg_envelope );
77 OpenSRF::Transport::PeerHandle->set_peer_client( $tran->get_peer_client );
78 OpenSRF::Transport::Listener->set_listener( $tran->get_listener );
84 # ----------------------------------------------
88 # put $instance in a closure and return it for requests to new()
89 # since there should only be one System instance running
92 sub instance { return __PACKAGE__->new(); }
97 $class = ref( $class ) || $class;
99 $self->{'pid_hash'} = {};
100 bless( $self, $class );
107 # ----------------------------------------------
108 # Commands to execute at system launch
112 return "OpenSRF::UnixServer->new( '$app' )->serve()";
117 return "OpenSRF::Transport::Listener->new( '$app' )->initialize()->listen()";
120 #sub _shell { return "OpenSRF::Shell->listen()"; }
123 # ----------------------------------------------
128 my $self = __PACKAGE__->instance();
130 my $config = OpenSRF::Utils::Config->current;
132 my $apps = $config->system->apps;
133 my $server_type = $config->system->server_type;
134 $server_type ||= "basic";
136 if( $server_type eq "prefork" ) {
137 $server_type = "Net::Server::PreForkSimple";
139 $server_type = "Net::Server::Single";
142 _log( " * Server type: $server_type", INTERNAL );
144 eval "use $server_type";
147 throw OpenSRF::EX::PANIC ("Cannot set $server_type: $@" );
150 push @OpenSRF::UnixServer::ISA, $server_type;
152 _log( " * System boostrap" );
154 # Start a process group and make me the captain
159 # --- Boot the Unix servers
160 $self->launch_unix($apps);
164 # --- Boot the listeners
165 $self->launch_listener($apps);
169 # --- Start the system shell
170 #if ($config->system->shell) {
172 # use OpenSRF::Shell;
173 # $self->launch_shell() if ($config->system->shell);
177 # warn "ARRRGGG! Can't start the shell...";
181 # --- Now we wait for our brood to perish
182 _log( " * System is ready..." );
183 while( 1 ) { sleep; }
189 # ----------------------------------------------
190 # Bootstraps a single client connection.
192 sub bootstrap_client {
194 my $self = __PACKAGE__->instance();
195 my $config = OpenSRF::Utils::Config->current;
199 OpenSRF::Transport::PeerHandle->construct( $app );
203 sub bootstrap_logger {
206 OpenSRF::Utils::LogServer->serve();
211 # ----------------------------------------------
212 # Cycle through the known processes, reap the dead child
213 # and put a new child in its place. (MMWWAHAHHAHAAAA!)
215 sub process_automation {
217 my $self = __PACKAGE__->instance();
219 foreach my $pid ( keys %{$self->pid_hash} ) {
221 if( waitpid( $pid, WNOHANG ) == $pid ) {
223 my $method = $self->pid_hash->{$pid};
224 delete $self->pid_hash->{$pid};
226 my $newpid = OpenSRF::Utils::safe_fork();
227 _log( "Relaunching => $method" );
230 $self->pid_hash( $newpid, $method );
232 else { $0 = $method; eval $method; exit; }
236 $SIG{CHLD} = \&process_automation;
240 # ----------------------------------------------
241 # Launch the Unix Servers
244 my( $self, $apps ) = @_;
246 foreach my $app ( @$apps ) {
248 _log( " * Starting UnixServer for $app..." );
250 my $pid = OpenSRF::Utils::safe_fork();
252 $self->pid_hash( $pid , _unixserver( $app ) );
256 $apname =~ tr/[a-z]/[A-Z]/;
257 $0 = "Unix Server ($apname)";
258 eval _unixserver( $app );
264 # ----------------------------------------------
265 # Launch the inbound clients
267 sub launch_listener {
269 my( $self, $apps ) = @_;
271 foreach my $app ( @$apps ) {
273 _log( " * Starting Listener for $app..." );
275 my $pid = OpenSRF::Utils::safe_fork();
277 $self->pid_hash( $pid , _listener( $app ) );
281 $apname =~ tr/[a-z]/[A-Z]/;
282 $0 = "Listener ($apname)";
283 eval _listener( $app );
289 # ----------------------------------------------
296 my $pid = OpenSRF::Utils::safe_fork();
298 if( $pid ) { $self->pid_hash( $pid , _shell() ); }
301 for( my $x = 0; $x != 10; $x++ ) {
311 # ----------------------------------------------
314 my( $self, $pid, $method ) = @_;
315 $self->{'pid_hash'}->{$pid} = $method
316 if( $pid and $method );
317 return $self->{'pid_hash'};
320 # ----------------------------------------------
321 # If requested, the System can shut down.
325 $SIG{CHLD} = 'IGNORE';
326 $SIG{INT} = 'IGNORE';
327 kill( 'INT', -$$ ); #kill all in process group
332 # ----------------------------------------------
336 _log( "HUPping brood" );
337 $SIG{CHLD} = 'IGNORE';
338 $SIG{HUP} = 'IGNORE';
339 set_config(); # reload config
341 # $SIG{CHLD} = \&process_automation;
342 $SIG{HUP} = sub{ instance()->hupall(); };
346 # ----------------------------------------------
347 # Log to debug, and stdout
351 OpenSRF::Utils::Logger->debug( $string );
352 print $string . "\n";
355 # ----------------------------------------------
358 select( undef, undef, undef, 0.3 );