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";
15 =head2 Name/Description
19 To start the system: OpenSRF::System->bootstrap();
21 Simple system process management and automation. After instantiating the class, simply call
22 bootstrap() to launch the system. Each launched process is stored as a process-id/method-name
23 pair in a local hash. When we receive a SIG{CHILD}, we loop through this hash and relaunch
24 any child processes that may have terminated.
26 Currently automated processes include launching the internal Unix Servers, launching the inbound
27 connections for each application, and starting the system shell.
30 Note: There should be only one instance of this class
31 alive at any given time. It is designed as a globel process handler and, hence, will cause much
32 oddness if you call the bootstrap() method twice or attempt to create two of these by trickery.
33 There is a single instance of the class created on the first call to new(). This same instance is
34 returned on subsequent calls to new().
40 sub APPS { return qw( opac ); } #circ cat storage ); }
44 # ----------------------------------------------
46 $SIG{INT} = sub { instance()->killall(); };
48 $SIG{HUP} = sub{ instance()->hupall(); };
50 #$SIG{CHLD} = \&process_automation;
53 # Go ahead and set the config
57 # ----------------------------------------------
61 my $config = OpenSRF::Utils::Config->load(
62 config_file => "/pines/conf/oils.conf" );
64 if( ! $config ) { throw OpenSRF::EX::Config "System could not load config"; }
66 my $tran = $config->transport->implementation;
70 throw OpenSRF::EX::PANIC ("Cannot find transport implementation: $@" );
73 OpenSRF::Transport->message_envelope( $tran->get_msg_envelope );
74 OpenSRF::Transport::PeerHandle->set_peer_client( $tran->get_peer_client );
75 OpenSRF::Transport::Listener->set_listener( $tran->get_listener );
85 # ----------------------------------------------
89 # put $instance in a closure and return it for requests to new()
90 # since there should only be one System instance running
93 sub instance { return __PACKAGE__->new(); }
98 $class = ref( $class ) || $class;
100 $self->{'pid_hash'} = {};
101 bless( $self, $class );
108 # ----------------------------------------------
109 # Commands to execute at system launch
113 return "OpenSRF::UnixServer->new( '$app' )->serve()";
118 return "OpenSRF::Transport::Listener->new( '$app' )->initialize()->listen()";
121 #sub _shell { return "OpenSRF::Shell->listen()"; }
124 # ----------------------------------------------
129 my $self = __PACKAGE__->instance();
131 my $config = OpenSRF::Utils::Config->current;
133 my $apps = $config->system->apps;
134 my $server_type = $config->system->server_type;
135 $server_type ||= "basic";
137 if( $server_type eq "prefork" ) {
138 $server_type = "Net::Server::PreForkSimple";
140 $server_type = "Net::Server::Single";
143 _log( " * Server type: $server_type", INTERNAL );
145 eval "use $server_type";
148 throw OpenSRF::EX::PANIC ("Cannot set $server_type: $@" );
151 push @OpenSRF::UnixServer::ISA, $server_type;
153 _log( " * System boostrap" );
155 # Start a process group and make me the captain
160 # --- Boot the Unix servers
161 $self->launch_unix($apps);
165 # --- Boot the listeners
166 $self->launch_listener($apps);
170 # --- Start the system shell
171 #if ($config->system->shell) {
173 # use OpenSRF::Shell;
174 # $self->launch_shell() if ($config->system->shell);
178 # warn "ARRRGGG! Can't start the shell...";
182 # --- Now we wait for our brood to perish
183 _log( " * System is ready..." );
184 while( 1 ) { sleep; }
190 # ----------------------------------------------
191 # Bootstraps a single client connection.
193 sub bootstrap_client {
195 my $self = __PACKAGE__->instance();
196 my $config = OpenSRF::Utils::Config->current;
200 OpenSRF::Transport::PeerHandle->construct( $app );
204 sub bootstrap_logger {
207 OpenSRF::Utils::LogServer->serve();
212 # ----------------------------------------------
213 # Cycle through the known processes, reap the dead child
214 # and put a new child in its place. (MMWWAHAHHAHAAAA!)
216 sub process_automation {
218 my $self = __PACKAGE__->instance();
220 foreach my $pid ( keys %{$self->pid_hash} ) {
222 if( waitpid( $pid, WNOHANG ) == $pid ) {
224 my $method = $self->pid_hash->{$pid};
225 delete $self->pid_hash->{$pid};
227 my $newpid = OpenSRF::Utils::safe_fork();
228 _log( "Relaunching => $method" );
231 $self->pid_hash( $newpid, $method );
233 else { $0 = $method; eval $method; exit; }
237 $SIG{CHLD} = \&process_automation;
241 # ----------------------------------------------
242 # Launch the Unix Servers
245 my( $self, $apps ) = @_;
247 foreach my $app ( @$apps ) {
249 _log( " * Starting UnixServer for $app..." );
251 my $pid = OpenSRF::Utils::safe_fork();
253 $self->pid_hash( $pid , _unixserver( $app ) );
257 $apname =~ tr/[a-z]/[A-Z]/;
258 $0 = "Unix Server ($apname)";
259 eval _unixserver( $app );
265 # ----------------------------------------------
266 # Launch the inbound clients
268 sub launch_listener {
270 my( $self, $apps ) = @_;
272 foreach my $app ( @$apps ) {
274 _log( " * Starting Listener for $app..." );
276 my $pid = OpenSRF::Utils::safe_fork();
278 $self->pid_hash( $pid , _listener( $app ) );
282 $apname =~ tr/[a-z]/[A-Z]/;
283 $0 = "Listener ($apname)";
284 eval _listener( $app );
290 # ----------------------------------------------
297 my $pid = OpenSRF::Utils::safe_fork();
299 if( $pid ) { $self->pid_hash( $pid , _shell() ); }
302 for( my $x = 0; $x != 10; $x++ ) {
312 # ----------------------------------------------
315 my( $self, $pid, $method ) = @_;
316 $self->{'pid_hash'}->{$pid} = $method
317 if( $pid and $method );
318 return $self->{'pid_hash'};
321 # ----------------------------------------------
322 # If requested, the System can shut down.
326 $SIG{CHLD} = 'IGNORE';
327 $SIG{INT} = 'IGNORE';
328 kill( 'INT', -$$ ); #kill all in process group
333 # ----------------------------------------------
337 _log( "HUPping brood" );
338 $SIG{CHLD} = 'IGNORE';
339 $SIG{HUP} = 'IGNORE';
340 set_config(); # reload config
342 # $SIG{CHLD} = \&process_automation;
343 $SIG{HUP} = sub{ instance()->hupall(); };
347 # ----------------------------------------------
348 # Log to debug, and stdout
352 OpenSRF::Utils::Logger->debug( $string );
353 print $string . "\n";
356 # ----------------------------------------------
359 select( undef, undef, undef, 0.3 );