#!/usr/bin/perl

#===============================================================================
# called by init.d script to control HILIS4 fastcgiexternalserver
# need to run as root to get uid change on fastcgi socket
# need to set fastcgiexternalserver socket path in httpd.conf
# run as lims_fastcgi_<centre> [start|stop|restart|status] + 2nd arg optional
# for tmp pid file for use while main processes restarted 
#===============================================================================

use strict;
use warnings;

use lib '/home/raj/perl5/lib/perl5'; 

use FCGI::ProcManager;
use Daemon::Control;
use Data::Dumper;
use CGI::Fast();
use FCGI;

use FindBin qw($Bin);  # load AFTER local::lib Carp or FindBin loads system
use lib "$Bin/../lib"; # Carp, causing fastcgi errors on Deb6
use LIMS::Dispatch;

# use User::pwent; # getpwnam() - done by Daemon::Control now

# APACHE_USER, CENTRE & NPROCS vars set in init.d:
my $CENTRE = $ENV{CENTRE}       || die 'no CENTRE env var set'; # warn $CENTRE;
my $GROUP  = $ENV{APACHE_GROUP} || die 'no APACHE_GROUP env var set'; # warn $GROUP;
my $USER   = $ENV{APACHE_USER}  || die 'no APACHE_USER env var set'; # warn $USER;
my $NPROCS = $ENV{NPROCESSES}   || 2; # use 2 if not defined

# $ARGV[0] is control command (start, stop, status, etc), $ARGV[1] is centre:
# my $CENTRE = $ARGV[1] || die 'need "centre" as 2nd arg'; # alternate method

#-------------------------------------------------------------------------------
my $run_dir = '/var/run/hilis4'; # location of pid file, socket, stderr
my $self = $0; # warn $self; # this script
# get uid of apache user using User::pwent::getpwnam: done by Daemon::Control now
# my $uid  = getpwnam($USER)->uid; # warn Dumper $uid; exit;
#-------------------------------------------------------------------------------

# define pid, stderr & stdout:
my $stderr = my $stdout = $run_dir . '/stderr.out'; # combine
my $pid_file = sprintf '%s.pid', join '/', $run_dir, $CENTRE; # warn $pid_file;

# if 2rd arg passed in @ARGV, assumes request for new temp pidfile -> same socket:
if ($ARGV[1]) { # $ARGV[0] is control command (start, stop, status, etc)
    $NPROCS = 1; # only need 1 for temp process
    $pid_file .= '~'; # creates new pid file for use while main processes restarted
} # warn Dumper [$pid_file, $NPROCS];

my %args = (
    name         => 'HILIS4_' . $CENTRE,
#    lsb_start   => '$syslog $remote_fs',
#    lsb_stop    => '$syslog',
    lsb_sdesc    => 'HILIS4 daemon',
    lsb_desc     => 'Controls the HILIS4 fastcgiexternalserver',
    path         => $self, # this script
    program      => \&hilis4, # $program - using sub {} now
    program_args => [ ],
    
    pid_file     => $pid_file,
    stderr_file  => $stderr,
    stdout_file  => $stdout,
	
	user         => $USER,
    group        => $GROUP,
    fork         => 2,
);

Daemon::Control->new(\%args)->run;

#-------------------------------------------------------------------------------

sub hilis4 {
	my $socket  = FCGI::OpenSocket( "$run_dir/$CENTRE.socket", 2 ); # path, backlog
	my $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket );
	
	print "FastCGI daemon started (pid $$)\n"; # prints to stdout (set in daemon control script)
	open STDIN,  "+</dev/null" or die $!;
	open STDOUT, ">&STDIN"     or die $!;
	open STDERR, ">&STDIN"     or die $!;
	
	my $proc_manager = FCGI::ProcManager->new({ n_processes => $NPROCS });
	
	# create PID file, unless already created by other process (eg Daemon::Control):
	if (! -e $pid_file) { # warn 'here';
	   $proc_manager->pm_write_pid_file($pid_file);
	}
	
	$proc_manager->pm_manage();
	
	$CGI::Fast::Ext_Request = $request;
	
	while ( my $query = CGI::Fast->new() ) {
		# set active db to production - default is `test`:
		$ENV{ROSEDB_DEVINIT} = "$Bin/../config/rosedb_devinit_prod.pl";
		# set flag for LIMS::_set_cgisession_options & QueryLog:
		$ENV{FAST_CGI} = 1;
		# switch LIMS::RDBO $Rose::DB::Object::Debug on
		$ENV{RDBO_DEBUG} = 1; 
		# set DBI trace:
		# $ENV{DBI_TRACE} = "1=$Bin/../logs/trace.log";
		
		$proc_manager->pm_pre_dispatch();
		
		eval {
			LIMS::Dispatch->dispatch(
				args_to_new => { QUERY => $query },
				default => '',
				debug => 0,
			);
		};
		my $err = $@;
		if ($err) {
			warn "$0 error: $err";
			exit 0; # to free $dbh from stuck transaction and restart process(es)
		}
		
		$proc_manager->pm_post_dispatch();
	}
	FCGI::CloseSocket( $socket );
}

__END__

example init.d scripts:

================================================================================
#!/bin/sh

export CENTRE=leeds
export NPROCESSES=2

. /etc/init.d/lims_fastcgi

================================================================================
#!/bin/sh

export APACHE_USER=www-data
export APACHE_GROUP=www

SCRIPT_DIR=/home/raj/apps/HILIS4/script
SCRIPT=hilis4.fgci

if [ -x $SCRIPT_DIR/$SCRIPT ];
then
    /usr/bin/perl $SCRIPT_DIR/$SCRIPT $@
else
    echo "Required program $SCRIPT_DIR/$SCRIPT not found!"
    exit 1;
fi

