Skip to content

Hypnotoad prefork web server

awohld edited this page Dec 6, 2014 · 13 revisions

Hypnotoad Prefork Web Server

Mojo::Server::Hypnotoad is built-in prefork web server in production environment. hypnotoad is command line interface to run Mojolicious application by Mojo::Server::Hypnotoad.

Management

Start Server

Start Server.

hypnotoad myapp.pl

Server start on port 8080 by default. you can access it from web browser.

http://localhost:8080

Process ID file is created in the same directory.

hypnotoad.pid

Stop Server

hypnotoad myapp.pl --stop

Hot Deployment Restart

hypnotoad myapp.pl

Hypnotoad will finish responding to existing requests; all new requests will use the reloaded code.

How to start server automatically after OS start on Unix

If you want to run server from root user, you switch application user and type hypnotoad command.

su - appuser -c 'hypnotoad $HOME/webapp/myapp/myapp.pl'

And you add this into OS startup config file such as rc.local

/etc/rc.d/rc.local

Access through proxy server

In production deployment, generally proxy server is used to access hypnotoad server. The following is apache/mod_proxy config file example using virtual host.

<VirtualHost *:80>

   ServerName app1.somehost.com
   ProxyPass / http://localhost:8080/
   ProxyPassReverse / http://localhost:8080/

    </VirtualHost>

See Apache deployment in detail.

Tips

Database connection problem in preforking

If you connect to database before preforking server and you use the connection to execute SQL, You see the following error in log or STDERR, for example, in MySQL.

MySQL server has gone away

The most simple solution is that you connect to database after preforking server. so you can establish the following two rules.

1. you must not connect to database in startup method.
2. Database initialization process must be written as default value of has function or attr method.

The following is Mojolicious and Mojolicious::Lite example.

Mojolicious:

package MyApp;
use Mojo::Base 'Mojolicious';

use DBI;

has dbh => sub {
    my $self = shift;
    
    my $data_source = "dbi:mysql:database=usertest";
    my $user = "ken";
    my $password = "ijdiuef";
    
    my $dbh = DBI->connect(
        $data_source,
        $user,
        $password,
        {RaiseError => 1}
    );

    return $dbh;
};

sub startup {
    my $self = shift;
    
    # You must not connect to database.

    # Routes
    my $r = $self->routes;

    # Normal route to controller
    $r->route('/welcome')->to('example#welcome');
}

1;

You use dbh from controller.

package MyApp::Example;
use Mojo::Base 'Mojolicious::Controller';

# This action will render a template
sub welcome {
    my $self = shift;
    
    my $dbh = $self->app->dbh;
    
    my $sth = $dbh->prepare('select * from table1');
    
    $sth->execute;
    
    $self->render(text => 'Hello');
}

1;

Mojolicious::Lite

use Mojolicious::Lite;

use DBI;

# You must not connect to database in this location

# dbh attribute
app->attr(dbh => sub {
    my $self = shift;
    
    my $data_source = "dbi:mysql:database=test";
    my $user = undef;
    my $password = undef;
    
    my $dbh = DBI->connect($data_source, $user, $password);
    
    return $dbh;
});

get '/' => sub {
    my $self = shift;
    
    my $dbh = $self->app->dbh;
    
    my $sth = $dbh->prepare('select * from table1');
    
    $sth->execute;
    
    $self->render(text => 'Hello');
};

app->start;

DBIx::Connector

Best way to to solve database connection problem in preforking is using DBIx::Connector. DBIx::Connector is database connection manager. Even if database connection is closed, the connection is automatically reconnected.

my $connector = DBIx::Connector->new(
    "dbi:mysql:database=$database",
    $user,
    $password,
);

my $dbh = $connector->dbh;

Some DBI wrapper modules support DBIx::Connector.

DBIx::Custom support DBIx::Connector.

my $connector = DBIx::Connector->new(
    "dbi:mysql:database=$database",
    $user,
    $password,
    {
        %{DBIx::Custom->new->default_dbi_option},
        mysql_enable_utf8 => 1
    }
);
my $dbi = DBIx::Custom->connect(connector => $connector);

Clone this wiki locally