OpenSRF client disconnect robustification (Perl)
[OpenSRF.git] / src / perl / lib / 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($logger);
6 use OpenSRF::Transport::Listener;
7 use OpenSRF::Transport;
8 use OpenSRF::Utils;
9 use OpenSRF::EX qw/:try/;
10 use POSIX qw/setsid :sys_wait_h/;
11 use OpenSRF::Utils::Config; 
12 use OpenSRF::Utils::SettingsParser;
13 use OpenSRF::Utils::SettingsClient;
14 use OpenSRF::Application;
15 use OpenSRF::Server;
16
17 my $bootstrap_config_file;
18 sub import {
19     my( $self, $config ) = @_;
20     $bootstrap_config_file = $config;
21 }
22
23 $| = 1;
24
25 sub DESTROY {}
26
27 sub load_bootstrap_config {
28     return if OpenSRF::Utils::Config->current;
29
30     die "Please provide a bootstrap config file to OpenSRF::System\n"
31         unless $bootstrap_config_file;
32
33     OpenSRF::Utils::Config->load(config_file => $bootstrap_config_file);
34     OpenSRF::Utils::JSON->register_class_hint(name => "OpenSRF::Application", hint => "method", type => "hash");
35     OpenSRF::Transport->message_envelope("OpenSRF::Transport::SlimJabber::MessageWrapper");
36     OpenSRF::Transport::PeerHandle->set_peer_client("OpenSRF::Transport::SlimJabber::PeerConnection");
37     OpenSRF::Application->server_class('client');
38     # Read in a shared portion of the config file
39     # for later use in log parameter redaction
40     $OpenSRF::Application::shared_conf = OpenSRF::Utils::Config->load(
41         'config_file' => OpenSRF::Utils::Config->current->FILE,
42         'nocache' => 1,
43         'force' => 1,
44         'base_path' => '/config/shared'
45     );
46 }
47
48 # ----------------------------------------------
49 # Bootstraps a single client connection.  
50 # named params are 'config_file' and 'client_name'
51 sub bootstrap_client {
52     my $self = shift;
53
54     my $con = OpenSRF::Transport::PeerHandle->retrieve;
55     if ($con) {
56         # flush the socket to force a non-blocking read
57         # and to clear out any unanticipated leftovers
58         eval { $con->flush_socket };
59         return if $con->connected;
60         $con->reset;
61     }
62
63     my %params = @_;
64
65     $bootstrap_config_file = 
66         $params{config_file} || $bootstrap_config_file;
67
68     my $app = $params{client_name} || "client";
69
70     load_bootstrap_config();
71     OpenSRF::Utils::Logger::set_config();
72     OpenSRF::Transport::PeerHandle->construct($app);
73 }
74
75 sub connected {
76     if (my $con = OpenSRF::Transport::PeerHandle->retrieve) {
77         return 1 if $con->connected;
78     }
79     return 0;
80 }
81
82 sub run_service {
83     my($class, $service, $pid_dir) = @_;
84
85     $0 = "OpenSRF Listener [$service]";
86
87     # temp connection to use for application initialization
88     OpenSRF::System->bootstrap_client(client_name => "system_client");
89
90     my $sclient = OpenSRF::Utils::SettingsClient->new;
91     my $getval = sub { $sclient->config_value(apps => $service => @_); };
92
93     my $impl = $getval->('implementation');
94
95     OpenSRF::Application::server_class($service);
96     OpenSRF::Application->application_implementation($impl);
97     OpenSRF::Utils::JSON->register_class_hint(name => $impl, hint => $service, type => 'hash');
98     OpenSRF::Application->application_implementation->initialize()
99         if (OpenSRF::Application->application_implementation->can('initialize'));
100
101     # kill the temp connection
102     OpenSRF::Transport::PeerHandle->retrieve->disconnect;
103     
104     # if this service does not want stderr output, it will be redirected to /dev/null
105     my $disable_stderr = $getval->('disable_stderr') || '';
106     my $stderr_path = ($disable_stderr =~ /true/i) ? undef : $sclient->config_value(dirs => 'log');
107
108     my $server = OpenSRF::Server->new(
109         $service,
110         keepalive => $getval->('keepalive') || 5,
111         max_requests =>  $getval->(unix_config => 'max_requests') || 10000,
112         max_children =>  $getval->(unix_config => 'max_children') || 20,
113         min_children =>  $getval->(unix_config => 'min_children') || 1,
114         min_spare_children =>  $getval->(unix_config => 'min_spare_children'),
115         max_spare_children =>  $getval->(unix_config => 'max_spare_children'),
116         stderr_log_path => $stderr_path
117     );
118
119     while(1) {
120         eval { $server->run; };
121         # we only arrive here if the server died a painful death
122         $logger->error("server: died with error $@");
123         $server->cleanup(1);
124         $logger->info("server: restarting after fatal crash...");
125         sleep 2;
126     }
127 }
128
129
130 1;