I have an interesting dilemna. It's a problem that keeps coming back to haunt me, and I've never solved it. I've searched and struggled and pondering and hacked away, but no luck. Will you help me?
We run Mason as a FastCGI script that listens on a socket. Our web server, nginx, sends requests to that socket. Now, in our case it's a unix domain socket, but certainly it could be TCP with little trouble. In the olden days, we had a nasty cascade of shell and perl scripts that would run the Mason application. Somewhere along the line, it would export the FCGI_SOCKET_PATH environment variable. There was only one script and only one socket and only one connection. This worked, but it was wrong, and we outgrew it. I rewrote the Mason application recently, and the work-in-progress appears below. It's not working yet, but it needs to be smarter now: it will read the number of children from my site configuration file, and fork() off children and patiently wait for them to do their service. All of it works except the CGI handler part, and only because of a problem with the environment variable. This is strange, because I set it within the perl process just before handling the CGI object. The SAME process. That is, I do this: $ENV{FCGI_SOCKET_PATH} = "$vhost_path/tmp/fcgi-$num.sock"; while ($cgi = new CGI::Fast) { $h = HTML::Mason::CGIHandler->new(%various_params); $h->handle_cgi_object($cgi); #### <--- crashes here } (This is abbreviated substantially; the full non-working script appears below.) Mason then delivers up this error message: Component path given to Interp->load must be absolute (was given ) It's not exactly informative. But it goes away when CGI::Fast is satisfied. Meanwhile, if I export the variable from the shell it can see it. The problem with that is that it needs to have N different values, one for each worker process. What I don't understand is why I can't see FCGI_SOCKET_PATH from the same process. Why doesn't CGI::Fast have the same %ENV when I call it just a few lines later? Is there some other more robust way to get that socket to CGI::Fast than the creaking and rickety old unix environment? Any help that anyone can give me would be greatly appreciated. -- Patrick .------ Patrick M. Jordan ------. Random unused band name: | Systems/Network Administrator | The Knights Who Say Nietzsche `------ Antistatic Matrix ------' #!/usr/bin/perl use Cwd qw(abs_path); use File::Basename; use YAML qw(LoadFile); use HTML::Mason::CGIHandler; use CGI::Fast; use strict; my %children; my ($conf, $last_conf_timestamp); my $vhost_path = abs_path(dirname($0) . '/..'); my $vhost_name = (split /\//, $vhost_path)[-1]; my $pid_file_name = $vhost_path . "/tmp/application.pid"; my $site_conf_filename = $vhost_path . '/etc/site.yaml'; sub site_conf_timestamp{ (stat $site_conf_filename)[9] } sub load_site_conf { return 0 if (&site_conf_timestamp == $last_conf_timestamp); # still current $last_conf_timestamp = &site_conf_timestamp; $conf = LoadFile($site_conf_filename); return 1; } BEGIN { $vhost_path = abs_path(dirname($0) . '/..'); $vhost_name = (split /\//, $vhost_path)[-1]; $site_conf_filename = $vhost_path . '/etc/site.yaml'; &load_site_conf; my $sentinel = 'MASON_ORACLE_VARS'; unless($ENV{$sentinel}) { $ENV{$sentinel} = 'SET'; $ENV{'LD_LIBRARY_PATH'} = $conf->{database}{dir} . '/lib'; $ENV{'TNS_ADMIN'} = $conf->{database}{tns_admin} ; exec $^X, $0, @ARGV; } } #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::| main |:: my $command = shift @ARGV; if ($command eq 'start') { &start } elsif ($command eq 'stop') { &stop } elsif ($command eq 'restart') { &stop; sleep 1; &start } else { die "usage: $0 (start|stop|restart)\n" } #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::| subs |:: sub start { if (-e $pid_file_name) { open PID, "$pid_file_name"; my $pid = readline PID; close PID; die "master process already running ($pid)\n"; } &parent; } sub stop { unless (-e $pid_file_name) { die "master process not running\n"; } open PID, "$pid_file_name"; my $pid = readline PID; close PID; kill 1, $pid; unlink $pid_file_name; } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sub shutdown { foreach my $pid (keys %children) { kill 1, $pid; } unlink $pid_file_name; } sub parent { exit if fork; open PID, ">$pid_file_name"; print PID $$; close PID; $0 = $vhost_name . ": master process"; for my $num (1 .. 1) { if (my $pid = fork) { $children{$pid} = $num; } else { &child($num); exit; } } close STDIN; close STDOUT; $SIG{INT} = 'shutdown'; $SIG{HUP} = 'shutdown'; $SIG{TERM} = 'shutdown'; $SIG{QUIT} = 'shutdown'; 1 while wait != -1; unlink $pid_file_name; } sub child { my $num = shift; $0 = $vhost_name . ": fastcgi worker [$num]"; { package HTML::Mason::Commands; use DBI; use DBD::Oracle qw(:ora_types); # for ORA_RSET use URI; use URI::Split; use Business::CreditCard; # Checksum credit cards use CGI::Cookie; use Cache::FileCache; use Crypt::PasswdMD5; use Data::Validate::Domain; use Date::Manip; use Digest::SHA1 qw(sha1_hex sha1_base64); use Email::Valid; use HTML::Entities qw(:DEFAULT encode_entities); use Mail::Send; use Net::Domain::TLD; use OSSP::uuid; use YAML qw(LoadFile); use vars ( '%SITE', # master data hash for all sites #-- Localized per-request variables '$Site', # Shorthand ref to $SITE{$ENV{SITE_FQDN}} '$Conf', # Shorthand ref to $Site->{conf} '$Form', # Params from GET and POST '$DB', # Persistent DB handle '%DB', # Persistent DB handle '@DEBUG', # Debug-level info accumulators '@DB_INFO', '@MESSAGE', # Messages to the user presented out-of-order '$TitleMod', # local mods to titles for better bookmarking '%Cookie', # cookies '$ORA_RSET', # shorthand for DBD::Oracle's rowset data type ); } sub HTML::Mason::FakeApache::param { my ($self, $key) = (@_); my %args = HTML::Mason::Utils::cgi_request_args( $self->query, $self->query->request_method ); return ($key ? $args{$key} : keys %args); } my %cgi_handler_params = ( default => { comp_root => "$vhost_path/html/", #data_dir => "$vhost_path/tmp", autohandler_name => '_AUTO', dhandler_name => '_DEFAULT', autoflush => 0, enable_autoflush => 0, static_source_touch_file => "$vhost_path/etc/site.yaml", # TODO: Port Mason params formerly used under mod_perl. # cache_class => 'MemoryCache', # cache_depth => 4, # default_expires_in => '24 hours', }, debug => { error_mode => 'output', #error_format => 'html', error_format => 'line', static_source => 0, }, no_debug => { error_mode => 'fatal', error_format => 'line', static_source => 1, }, ); #%ENV = (); my $h; my $cgi; $ENV{FCGI_SOCKET_PATH} = "$vhost_path/tmp/fcgi-$num.sock"; eval { while ($cgi = new CGI::Fast) { if (!$h || &load_site_conf) { $h = HTML::Mason::CGIHandler->new( (%{$cgi_handler_params{default}}), ($conf->{debug} ? (%{$cgi_handler_params{debug}}) : (%{$cgi_handler_params{no_debug}}) ) ); } eval { $h->handle_cgi_object($cgi) }; if (my $raw_error = $@) { if ($@ =~ /could not find component for initial path/) { print "Status: 404\n\n"; next; # Or: # $cgi->path_info('/errordocs/404.html'); # $h->handle_cgi_object($cgi); } else { open GRAH, ">/tmp/grah.txt"; print GRAH "$raw_error\n"; print GRAH "----\n"; foreach my $k (sort keys %ENV) { print GRAH "$k: $ENV{$k}\n"; } close GRAH; warn $raw_error; } } } }; if (my $raw_error = $@) { open GRAH, ">/tmp/grah.txt"; print GRAH "$raw_error\n"; print GRAH "----\n"; foreach my $k (sort keys %ENV) { print GRAH "$k: $ENV{$k}\n"; } close GRAH; #warn $raw_error; } } ------------------------------------------------------------------------- This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/ _______________________________________________ Mason-users mailing list Mason-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mason-users