[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