[rt-users] spawn-fcgi and rt-server.fcgi fail
Alex Vandiver
alexmv at bestpractical.com
Fri Oct 19 14:32:12 EDT 2012
On Fri, 2012-10-19 at 12:21 -0500, Alex Hanselka wrote:
Upon strace-ing the file, it seems to have a lot of issues with "(No
> such file or directory)" errors. I assume this is because it searches
> for the files and the first places it tries are wrong?
Correct, those are expected as perl searches through @INC looking for
library files.
> I also see a bunch of "Inappropriate ioctl for device." I can provide
> a pastebin of the strace if necessary.
The ioctl error is somewhat more surprising. Seeing a pastebin of the
strace might be useful.
> As for my configure line, it was very simple: "./configure
> --with-web-user=nginx --with-web-group=nginx --with-db-type=Pg"... Did I
> miss something?
Nope. I just wanted to see the user and group you'd passed to
configure.
Re-reading your original mail, I'd expect the spawn-fcgi incant to work,
but the failure case of rt-server.fcgi not working with --port is a
known bug, and one which is resolved in the 4.2/refactor-rt-server
branch. I've included below a backport of the relevant commit; I'd be
curious to hear if it solves your problem or gives a more coherent error
message.
- Alex
------------------------------------ 8< -------------------------------
>From 0745a7c578ffb50ff17124334934fefdb0c61a2d Mon Sep 17 00:00:00 2001
From: Alex Vandiver <alexmv at bestpractical.com>
Date: Mon, 20 Jun 2011 21:58:30 -0400
Subject: [PATCH] Refactor rt-server.in into RT::PlackRunner
This properly detects --port, --listen, and --socket options, and falls
back to $WebPort only when none are specified. It also provides better
handling for fastcgi, detecting when STDIN is a socket, and bailing with
a correct error message if it has no other options to listen on.
diff --git a/lib/RT/PlackRunner.pm b/lib/RT/PlackRunner.pm
new file mode 100644
index 0000000..8a7ea3d
--- /dev/null
+++ b/lib/RT/PlackRunner.pm
@@ -0,0 +1,139 @@
+use warnings;
+use strict;
+
+package RT::PlackRunner;
+
+use base 'Plack::Runner';
+
+sub parse_options {
+ my $self = shift;
+ my @args = @_;
+ # handle "rt-server 8888" for back-compat, but complain about it
+ if (@args && $args[0] =~ m/^\d+$/) {
+ warn "Deprecated: please run $0 --port $ARGV[0] instead\n";
+ unshift @args, '--port';
+ }
+
+ $self->SUPER::parse_options(@args);
+
+ $self->{app} ||= $self->app;
+ $self->{server} ||= $self->loader->guess;
+
+ my %args = @{$self->{options}};
+ if ($self->{server} eq "FCGI") {
+ # We deal with the possible failure modes of this in ->run
+ } elsif ($args{port}) {
+ $self->{explicit_port} = 1;
+ my $old_app = $self->{app};
+ $self->{app} = sub {
+ my $env = shift;
+ $env->{'rt.explicit_port'} = $args{port};
+ $old_app->($env, @_);
+ };
+ } else {
+ $self->set_options(port => (RT->Config->Get('WebPort') || '8080'));
+ }
+}
+
+# Override to not default to port 5000
+sub mangle_host_port_socket {
+ my($self, $host, $port, $socket, @listen) = @_;
+
+ for my $listen (reverse @listen) {
+ if ($listen =~ /:\d+$/) {
+ ($host, $port) = split /:/, $listen, 2;
+ $host = undef if $host eq '';
+ } else {
+ $socket ||= $listen;
+ }
+ }
+
+ unless (@listen) {
+ if ($socket) {
+ @listen = ($socket);
+ } elsif ($port) {
+ @listen = ($host ? "$host:$port" : ":$port");
+ }
+ }
+
+ return host => $host, port => $port, listen => \@listen, socket => $socket;
+}
+
+sub prepare_devel {
+ my($self, $app) = @_;
+ # Don't install the Lint, StackTrace, and AccessLog middleware
+
+ push @{$self->{options}}, server_ready => sub {
+ my($args) = @_;
+ my $name = $args->{server_software} || ref($args);
+ my $host = $args->{host} || RT->Config->Get('WebDomain');
+ my $proto = $args->{proto} || 'http';
+ print STDERR "$name: Accepting connections at $proto://$host:$args->{port}/\n";
+ };
+
+ $app;
+}
+
+
+sub app {
+ require RT::Interface::Web::Handler;
+ my $app = RT::Interface::Web::Handler->PSGIApp;
+
+ if ($ENV{RT_TESTING}) {
+ my $screen_logger = $RT::Logger->remove('screen');
+ require Log::Dispatch::Perl;
+ $RT::Logger->add(
+ Log::Dispatch::Perl->new(
+ name => 'rttest',
+ min_level => $screen_logger->min_level,
+ action => {
+ error => 'warn',
+ critical => 'warn'
+ }
+ )
+ );
+ require Plack::Middleware::Test::StashWarnings;
+ $app = Plack::Middleware::Test::StashWarnings->wrap($app);
+ }
+
+ return $app;
+}
+
+sub run {
+ my $self = shift;
+
+ my %args = @{$self->{options}};
+
+ # Plack::Handler::FCGI has its own catch for this, but doesn't
+ # notice that listen is an empty list, and we can also provide a
+ # better error message.
+ if ($self->{server} eq "FCGI" and not -S STDIN and not @{$args{listen}}) {
+ print STDERR "STDIN is not a socket, and no --listen, --socket, or --port provided\n";
+ exit 1;
+ }
+
+ eval { $self->SUPER::run(@_) };
+ my $err = $@;
+ exit 0 unless $err;
+
+ if ( $err =~ /listen/ ) {
+ print STDERR <<EOF;
+WARNING: RT couldn't start up a web server on port $args{port}.
+This is often the case if the port is already in use or you're running @{[$0]}
+as someone other than your system's "root" user. You may also specify a
+temporary port with: $0 --port <port>
+EOF
+
+ if ($self->{explicit_port}) {
+ print STDERR
+ "Please check your system configuration or choose another port\n\n";
+ }
+ exit 1;
+ } else {
+ die
+ "Something went wrong while trying to run RT's standalone web server:\n\t"
+ . $err;
+ }
+}
+
+1;
diff --git a/sbin/rt-server b/sbin/rt-server
index f84f6c1..fccd895 100755
--- a/sbin/rt-server
+++ b/sbin/rt-server
@@ -99,7 +99,7 @@ my ($integrity, $state, $msg) = RT::Handle->CheckIntegrity;
unless ( $integrity ) {
print STDERR <<EOF;
-
+
RT couldn't connect to the database where tickets are stored.
If this is a new installation of RT, you should visit the URL below
to configure RT and initialize your database.
@@ -141,127 +141,20 @@ if ($RT::Handle) {
undef $RT::Handle;
}
-require RT::Interface::Web::Handler;
-my $app = RT::Interface::Web::Handler->PSGIApp;
-
-if ($ENV{RT_TESTING}) {
- my $screen_logger = $RT::Logger->remove('screen');
- require Log::Dispatch::Perl;
- $RT::Logger->add(
- Log::Dispatch::Perl->new(
- name => 'rttest',
- min_level => $screen_logger->min_level,
- action => {
- error => 'warn',
- critical => 'warn'
- }
- )
- );
- require Plack::Middleware::Test::StashWarnings;
- $app = Plack::Middleware::Test::StashWarnings->wrap($app);
-}
-
+require RT::PlackRunner;
# when used as a psgi file
if (caller) {
- return $app;
-}
-
-
-# load appropriate server
-
-require Plack::Runner;
-
-my $is_fastcgi = $0 =~ m/fcgi$/;
-my $r = Plack::Runner->new( $0 =~ /standalone/ ? ( server => 'Standalone' ) :
- $is_fastcgi ? ( server => 'FCGI' )
- : (),
- env => 'deployment' );
-
-# figure out the port
-my $port;
-
-# handle "rt-server 8888" for back-compat, but complain about it
-if ($ARGV[0] && $ARGV[0] =~ m/^\d+$/) {
- warn "Deprecated: please run $0 --port $ARGV[0] instead\n";
- unshift @ARGV, '--port';
-}
-
-my @args = @ARGV;
-
-use List::MoreUtils 'last_index';
-my $last_index = last_index { $_ eq '--port' } @args;
-
-my $explicit_port;
-
-if ( $last_index != -1 && $args[$last_index+1] =~ /^\d+$/ ) {
- $explicit_port = $args[$last_index+1];
- $port = $explicit_port;
-
- # inform the rest of the system what port we manually chose
- my $old_app = $app;
- $app = sub {
- my $env = shift;
-
- $env->{'rt.explicit_port'} = $port;
-
- $old_app->($env, @_);
- };
-}
-else {
- # default to the configured WebPort and inform Plack::Runner
- $port = RT->Config->Get('WebPort') || '8080';
- push @args, '--port', $port;
-}
-
-push @args, '--server', 'Standalone' if RT->InstallMode;
-push @args, '--server', 'Starlet' unless $r->{server} || grep { m/--server/ } @args;
-
-$r->parse_options(@args);
-
-delete $r->{options} if $is_fastcgi; ### mangle_host_port_socket ruins everything
-
-unless ($r->{env} eq 'development') {
- push @{$r->{options}}, server_ready => sub {
- my($args) = @_;
- my $name = $args->{server_software} || ref($args); # $args is $server
- my $host = $args->{host} || 0;
- my $proto = $args->{proto} || 'http';
- print STDERR "$name: Accepting connections at $proto://$host:$args->{port}/\n";
- };
-}
-eval { $r->run($app) };
-if (my $err = $@) {
- handle_startup_error($err);
+ return RT::PlackRunner->app;
}
-exit 0;
-
-sub handle_startup_error {
- my $err = shift;
- if ( $err =~ /listen/ ) {
- handle_bind_error();
- } else {
- die
- "Something went wrong while trying to run RT's standalone web server:\n\t"
- . $err;
- }
-}
+my $r = RT::PlackRunner->new( RT->InstallMode ? ( server => 'Standalone' ) :
+ $0 =~ /standalone/ ? ( server => 'Standalone' ) :
+ $0 =~ /fcgi$/ ? ( server => 'FCGI', env => "deployment" )
+ : ( server => 'Starlet', env => "deployment" ) );
+$r->parse_options(@ARGV);
+$r->run;
-sub handle_bind_error {
-
- print STDERR <<EOF;
-WARNING: RT couldn't start up a web server on port @{[$port]}.
-This is often the case if the port is already in use or you're running @{[$0]}
-as someone other than your system's "root" user. You may also specify a
-temporary port with: $0 --port <port>
-EOF
-
- if ($explicit_port) {
- print STDERR
- "Please check your system configuration or choose another port\n\n";
- }
-}
__END__
--
1.7.11.3
More information about the rt-users
mailing list