]> git.evergreen-ils.org Git - Evergreen.git/blob - OpenSRF/src/perlmods/OpenSRF/System.pm
remove method call that does not exist
[Evergreen.git] / OpenSRF / src / perlmods / OpenSRF / System.pm
1 package OpenSRF::System;
2 use strict; use warnings;
3 use OpenSRF;
4 use base 'OpenSRF';
5 use OpenSRF::Utils::Logger qw(:level);
6 use OpenSRF::Transport::Listener;
7 use OpenSRF::Transport;
8 use OpenSRF::UnixServer;
9 use OpenSRF::Utils;
10 use OpenSRF::Utils::LogServer;
11 use OpenSRF::DOM;
12 use OpenSRF::EX qw/:try/;
13 use POSIX ":sys_wait_h";
14 use OpenSRF::Utils::Config; 
15 use OpenSRF::Utils::SettingsParser;
16 use OpenSRF::Utils::SettingsClient;
17 use OpenSRF::Application;
18 use Net::Server::PreFork;
19 use strict;
20
21 my $bootstrap_config_file;
22 sub import {
23         my( $self, $config ) = @_;
24         $bootstrap_config_file = $config;
25 }
26
27 =head2 Name/Description
28
29 OpenSRF::System
30
31 To start the system: OpenSRF::System->bootstrap();
32
33 Simple system process management and automation.  After instantiating the class, simply call
34 bootstrap() to launch the system.  Each launched process is stored as a process-id/method-name
35 pair in a local hash.  When we receive a SIG{CHILD}, we loop through this hash and relaunch
36 any child processes that may have terminated.  
37
38 Currently automated processes include launching the internal Unix Servers, launching the inbound 
39 connections for each application, and starting the system shell.
40
41
42 Note: There should be only one instance of this class
43 alive at any given time.  It is designed as a globel process handler and, hence, will cause much
44 oddness if you call the bootstrap() method twice or attempt to create two of these by trickery.
45 There is a single instance of the class created on the first call to new().  This same instance is 
46 returned on subsequent calls to new().
47
48 =cut
49
50 $| = 1;
51
52 sub DESTROY {}
53
54 # ----------------------------------------------
55
56 $SIG{INT} = sub { instance()->killall(); };
57
58 $SIG{HUP} = sub{ instance()->hupall(); };
59
60 #$SIG{CHLD} = \&process_automation;
61
62
63
64         # --- 
65         # put $instance in a closure and return it for requests to new()
66         # since there should only be one System instance running
67         # ----- 
68         my $instance;
69         sub instance { return __PACKAGE__->new(); }
70         sub new {
71                 my( $class ) = @_;
72
73                 if( ! $instance ) {
74                         $class = ref( $class ) || $class;
75                         my $self = {};
76                         $self->{'pid_hash'} = {};
77                         bless( $self, $class );
78                         $instance = $self;
79                 }
80                 return $instance;
81         }
82 }
83
84 # ----------------------------------------------
85 # Commands to execute at system launch
86
87 sub _unixserver {
88         my( $app ) = @_;
89         return "OpenSRF::UnixServer->new( '$app')->serve()";
90 }
91
92 sub _listener {
93         my( $app ) = @_;
94         return "OpenSRF::Transport::Listener->new( '$app' )->initialize()->listen()";
95 }
96
97
98 # ----------------------------------------------
99 # Boot up the system
100
101 sub load_bootstrap_config {
102
103         if(OpenSRF::Utils::Config->current) {
104                 return;
105         }
106
107         if(!$bootstrap_config_file) {
108                 die "Please provide a bootstrap config file to OpenSRF::System!\n" . 
109                         "use OpenSRF::System qw(/path/to/bootstrap_config);";
110         }
111
112         OpenSRF::Utils::Config->load( config_file => $bootstrap_config_file );
113
114         JSON->register_class_hint( name => "OpenSRF::Application", hint => "method", type => "hash" );
115
116         OpenSRF::Transport->message_envelope(  "OpenSRF::Transport::SlimJabber::MessageWrapper" );
117         OpenSRF::Transport::PeerHandle->set_peer_client(  "OpenSRF::Transport::SlimJabber::PeerConnection" );
118         OpenSRF::Transport::Listener->set_listener( "OpenSRF::Transport::SlimJabber::Inbound" );
119         OpenSRF::Application->server_class('client');
120 }
121
122 sub bootstrap {
123
124         my $self = __PACKAGE__->instance();
125         load_bootstrap_config();
126         OpenSRF::Utils::Logger::set_config();
127         my $bsconfig = OpenSRF::Utils::Config->current;
128
129         # Start a process group and make me the captain
130         setpgrp( 0, 0 ); 
131         $0 = "OpenSRF System";
132
133         # -----------------------------------------------
134         # Launch the settings sever if necessary...
135         my $are_settings_server = 0;
136         if( (my $cfile = $bsconfig->bootstrap->settings_config) ) {
137                 my $parser = OpenSRF::Utils::SettingsParser->new();
138
139                 # since we're (probably) the settings server, we can go ahead and load the real config file
140                 $parser->initialize( $cfile );
141                 $OpenSRF::Utils::SettingsClient::host_config = 
142                         $parser->get_server_config($bsconfig->env->hostname);
143
144                 my $client = OpenSRF::Utils::SettingsClient->new();
145                 my $apps = $client->config_value("activeapps", "appname");
146                 if(ref($apps) ne "ARRAY") { $apps = [$apps]; }
147
148                 if(!defined($apps) || @$apps == 0) {
149                         print "No apps to load, exiting...";
150                         return;
151                 }
152
153                 for my $app (@$apps) {
154                         # verify we are a settings server and launch 
155                         if( $app eq "opensrf.settings" and 
156                                 $client->config_value("apps","opensrf.settings", "language") =~ /perl/i ) {
157
158                                 $are_settings_server = 1;
159                                 $self->launch_settings();
160                                 sleep 1;
161                                 $self->launch_settings_listener();
162                                 last;
163                         } 
164                 }
165         }
166
167         # Launch everything else
168         OpenSRF::System->bootstrap_client(client_name => "system_client");
169         my $client = OpenSRF::Utils::SettingsClient->new();
170         my $apps = $client->config_value("activeapps", "appname" );
171         if(!ref($apps)) { $apps = [$apps]; }
172
173         if(!defined($apps) || @$apps == 0) {
174                 print "No apps to load, exiting...";
175                 return;
176         }
177
178         my $server_type = $client->config_value("server_type");
179         $server_type ||= "basic";
180
181         my $con = OpenSRF::Transport::PeerHandle->retrieve;
182         if($con) {
183                 $con->disconnect;
184         }
185
186
187
188         if(  $server_type eq "prefork" ) { 
189                 $server_type = "Net::Server::PreFork"; 
190         } else { 
191                 $server_type = "Net::Server::Single"; 
192         }
193
194         _log( " * Server type: $server_type", INTERNAL );
195
196         $server_type->use;
197
198         if( $@ ) {
199                 throw OpenSRF::EX::PANIC ("Cannot set $server_type: $@" );
200         }
201
202         push @OpenSRF::UnixServer::ISA, $server_type;
203
204         _log( " * System boostrap" );
205         
206         # --- Boot the Unix servers
207         $self->launch_unix($apps);
208
209
210         _sleep();
211         sleep 2;
212
213         # --- Boot the listeners
214         $self->launch_listener($apps);
215
216         _sleep();
217
218         _log( " * System is ready..." );
219
220 #       sleep 1;
221 #       my $ps = `ps ax | grep " Open" | grep -v grep | sort -r -k5`;
222 #       print "\n --- PS --- \n$ps --- PS ---\n\n";
223
224         while( 1 ) { sleep; }
225         exit;
226 }
227         
228         
229
230 # ----------------------------------------------
231 # Bootstraps a single client connection.  
232
233 # named params are 'config_file' and 'client_name'
234 #
235 sub bootstrap_client {
236         my $self = shift;
237
238         my $con = OpenSRF::Transport::PeerHandle->retrieve;
239
240         if($con and $con->tcp_connected) {
241                 return;
242         }
243
244         my %params = @_;
245
246         $bootstrap_config_file = 
247                 $params{config_file} || $bootstrap_config_file;
248
249         my $app = $params{client_name} || "client";
250
251
252         load_bootstrap_config();
253         OpenSRF::Utils::Logger::set_config();
254         OpenSRF::Transport::PeerHandle->construct( $app );
255
256 }
257
258 sub connected {
259         if (my $con = OpenSRF::Transport::PeerHandle->retrieve) {
260                 return 1 if ($con->tcp_connected);
261         }
262         return 0;
263 }
264
265 sub bootstrap_logger {
266         $0 = "Log Server";
267         OpenSRF::Utils::LogServer->serve();
268 }
269
270
271 # ----------------------------------------------
272 # Cycle through the known processes, reap the dead child 
273 # and put a new child in its place. (MMWWAHAHHAHAAAA!)
274
275 sub process_automation {
276
277         my $self = __PACKAGE__->instance();
278
279         foreach my $pid ( keys %{$self->pid_hash} ) {
280
281                 if( waitpid( $pid, WNOHANG ) == $pid ) {
282
283                         my $method = $self->pid_hash->{$pid};
284                         delete $self->pid_hash->{$pid};
285
286                         my $newpid =  OpenSRF::Utils::safe_fork();
287
288                         OpenSRF::Utils::Logger->debug( "Relaunching $method", ERROR );
289                         _log( "Relaunching => $method" );
290
291                         if( $newpid ) {
292                                 $self->pid_hash( $newpid, $method );
293                         }
294                         else { eval $method; exit; }
295                 }
296         }
297
298         $SIG{CHLD} = \&process_automation;
299 }
300
301
302
303 sub launch_settings {
304
305         #       XXX the $self like this and pid automation will not work with this setup....
306         my($self) = @_;
307         @OpenSRF::UnixServer::ISA = qw(OpenSRF Net::Server::PreFork);
308
309         my $pid = OpenSRF::Utils::safe_fork();
310         if( $pid ) {
311                 $self->pid_hash( $pid , "launch_settings()" );
312         }
313         else {
314                 my $apname = "opensrf.settings";
315                 #$0 = "OpenSRF App [$apname]";
316                 eval _unixserver( $apname );
317                 if($@) { die "$@\n"; }
318                 exit;
319         }
320
321         @OpenSRF::UnixServer::ISA = qw(OpenSRF);
322
323 }
324
325
326 sub launch_settings_listener {
327
328         my $self = shift;
329         my $app = "opensrf.settings";
330         my $pid = OpenSRF::Utils::safe_fork();
331         if ( $pid ) {
332                 $self->pid_hash( $pid , _listener( $app ) );
333         }
334         else {
335                 my $apname = $app;
336                 $0 = "OpenSRF listener [$apname]";
337                 eval _listener( $app );
338                 exit;
339         }
340
341 }
342
343 # ----------------------------------------------
344 # Launch the Unix Servers
345
346 sub launch_unix {
347         my( $self, $apps ) = @_;
348
349         my $client = OpenSRF::Utils::SettingsClient->new();
350
351         foreach my $app ( @$apps ) {
352
353                 next unless $app;
354                 my $lang = $client->config_value( "apps", $app, "language");
355                 next unless $lang =~ /perl/i;
356                 next if $app eq "opensrf.settings";
357
358                 _log( " * Starting UnixServer for $app..." );
359
360                 my $pid = OpenSRF::Utils::safe_fork();
361                 if( $pid ) {
362                         $self->pid_hash( $pid , _unixserver( $app ) );
363                 }
364                 else {
365                         my $apname = $app;
366                         $0 = "OpenSRF App ($apname)";
367                         eval _unixserver( $app );
368                         exit;
369                 }
370         }
371 }
372
373 # ----------------------------------------------
374 # Launch the inbound clients
375
376 sub launch_listener {
377
378         my( $self, $apps ) = @_;
379         my $client = OpenSRF::Utils::SettingsClient->new();
380
381         foreach my $app ( @$apps ) {
382
383                 next unless $app;
384                 my $lang = $client->config_value( "apps", $app, "language");
385                 next unless $lang =~ /perl/i;
386                 next if $app eq "opensrf.settings";
387
388                 _log( " * Starting Listener for $app..." );
389
390                 my $pid = OpenSRF::Utils::safe_fork();
391                 if ( $pid ) {
392                         $self->pid_hash( $pid , _listener( $app ) );
393                 }
394                 else {
395                         my $apname = $app;
396                         $0 = "OpenSRF listener [$apname]";
397                         eval _listener( $app );
398                         exit;
399                 }
400         }
401 }
402
403 # ----------------------------------------------
404
405 =head comment
406 sub launch_shell {
407
408         my $self = shift;
409
410         my $pid = OpenSRF::Utils::safe_fork();
411
412         if( $pid ) { $self->pid_hash( $pid , _shell() ); }
413         else {
414                 $0 = "System Shell";
415                 for( my $x = 0; $x != 10; $x++ ) {
416                         eval _shell();
417                         if( ! $@ ) { last; }
418                 }
419                 exit;
420         }
421 }
422 =cut
423
424
425 # ----------------------------------------------
426
427 sub pid_hash {
428         my( $self, $pid, $method ) = @_;
429         $self->{'pid_hash'}->{$pid} = $method
430                 if( $pid and $method );
431         return $self->{'pid_hash'};
432 }
433
434 # ----------------------------------------------
435 # If requested, the System can shut down.
436
437 sub killall {
438
439         $SIG{CHLD} = 'IGNORE';
440         $SIG{INT} = 'IGNORE';
441         kill( 'INT', -$$ ); #kill all in process group
442         exit;
443
444 }
445
446 # ----------------------------------------------
447 # Handle $SIG{HUP}
448 sub hupall {
449
450         _log( "HUPping brood" );
451         $SIG{CHLD} = 'IGNORE';
452         $SIG{HUP} = 'IGNORE';
453         kill( 'HUP', -$$ );
454 #       $SIG{CHLD} = \&process_automation;
455         $SIG{HUP} = sub{ instance()->hupall(); };
456 }
457
458
459 # ----------------------------------------------
460 # Log to debug, and stdout
461
462 sub _log {
463         my $string = shift;
464         OpenSRF::Utils::Logger->debug( $string, INFO );
465         print $string . "\n";
466 }
467
468 # ----------------------------------------------
469
470 sub _sleep {
471         select( undef, undef, undef, 0.3 );
472 }
473
474 1;
475
476