Как мне провести рефакторинг кода Perl, который использует Template Toolkit с DBI, чтобы использовать преимущества FastCGI? - PullRequest
5 голосов
/ 04 июня 2009

Фон

Ниже приведен типичный фрагмент кода Perl ( sample.pl для обсуждения), который захватывает отправленные данные формы с помощью CGI, передает данные формы в DBI, который затем извлекает необходимые строки из MySQL а затем передает результаты в Template Toolkit для рендеринга в HTML-документ для отображения.

Список кодов для sample.pl :

#!/usr/bin/perl
use strict;
use CGI;
use DBI:
use Template;

#Grab submitted form data
my $cgi = CGI->new();
my $idFromSomewhere= $cgi->param('id');

my $driver   = "mysql";
my $server   = "localhost:3306";
my $database = "test";
my $url      = "DBI:$driver:$database:$server";
my $user     = "apache";
my $password = "";

#Connect to database
my $db_handle = DBI->connect( $url, $user, $password ) 
    or die $DBI::errstr;

#SQL query to execute
my $sql = "SELECT * FROM tests WHERE id=?";

#Prepare SQL query
my $statement = $db_handle->prepare($sql)
        or die "Couldn't prepare query '$sql': $DBI::errstr\n";

#Execute SQL Query
$statement->execute($idFromSomewhere)
    or die "Couldn't execute query '$sql': $DBI::errstr\n";

#Get query results as hash
my $results = $statement->fetchall_hashref('id');

$db_handle->disconnect();
my $tt = Template->new();

#HTML output template
my $input = 'template.html';
my $vars = {
    tests => $results,
};

#Process template and output as HTML
$tt->process($input, $vars)
    or die $tt->error();

Для повышения производительности и масштабируемости веб-хосты, предоставляющие общие серверы, такие как Dreamhost, настоятельно рекомендуют всем производственным сценариям Perl поддерживать FastCGI. В документации FastCGI достаточно ясно, как изменить существующий код Perl для поддержки FastCGI. Простой код ниже часто приводится в качестве примера:

use FCGI;
while (FCGI::accept >= 0)
{    
   #Run existing code.
}

Что не так понятно, так это где и что поместить в цикл while.

Дополнительные вопросы

A. Если код в sample.pl просто обернуть вокруг существующего кода следующим образом:

while (FCGI::accept >= 0)
{    
    #Grab submitted form data
    my $cgi = CGI->new();
    ...
    ...
    #Process template and output as HTML
    $tt->process($input, $vars)
    or die $tt->error();
}

B. Или есть что-то еще? Например, должен ли код, который обрабатывает cgi, базу данных и шаблон, быть реорганизован в свои собственные подпрограммы?

С Должны ли DBI-> connect () и $ db_handle-> disconnect () вызываться внутри или снаружи FCGI во время цикла и как это влияет на производительность?

D. Должен ли $ tt-> process () вызываться внутри или вне FCGI-цикла while?

Ответы [ 3 ]

10 голосов
/ 04 июня 2009

Если вы знакомы с CGI.pm, нет смысла использовать FCGI.pm, используйте CGI :: Fast.

Ваш пример, преобразованный для использования CGI :: Fast, будет:

#!/usr/bin/perl
use strict;
use CGI::Fast;
use DBI;
use Template;

my $driver   = "mysql";
my $server   = "localhost:3306";
my $database = "test";
my $url      = "DBI:$driver:$database:$server";
my $user     = "apache";
my $password = "";

#Connect to database
my $db_handle = DBI->connect( $url, $user, $password ) or die $DBI::errstr;

while ( my $cgi = CGI::Fast->new() ) {

    #Grab submitted form data
    my $idFromSomewhere = $cgi->param( 'id' );

    #SQL query to execute
    my $sql = "SELECT * FROM tests WHERE id=?";

    #Prepare SQL query
    my $statement = $db_handle->prepare( $sql )
        or die "Couldn't prepare query '$sql': $DBI::errstr\n";

    #Execute SQL Query
    $statement->execute( $idFromSomewhere )
        or die "Couldn't execute query '$sql': $DBI::errstr\n";

    #Get query results as hash
    my $results = $statement->fetchall_hashref( 'id' );

    my $tt = Template->new();

    #HTML output template
    my $input = 'template.html';
    my $vars = { tests => $results, };

    #Process template and output as HTML
    $tt->process( $input, $vars )
        or die $tt->error();
}

Что касается ваших подвопросов:

  • A: Не используйте FCGI, если вы не уверены на 100%, что знаете, что делаете. Вы определенно хотите CGI :: Fast:)
  • B: Я бы рефакторинг его для удобства чтения
  • C: если вы используете DBI-> connect до принятия соединения, вы получаете постоянное соединение с базой данных, что замечательно с точки зрения производительности
  • D: определенно внутри.

В качестве дополнительной информации - если вы хотите разрабатывать веб-сайты на Perl, хотя бы взгляните на Catalyst (http://www.catalystframework.org/)

1 голос
/ 05 июня 2009

Если вы хотите использовать FCGI, сделайте только минимум в этом цикле, чтобы запустить задачу. Все остальное должно жить в модулях, и все, что вам нужно сделать, это передать ввод.

use FCGI;
while (FCGI::accept >= 0)
    {    
    MyApplication->activate( @args );
    }

Все остальное находится где-то в MyApplication. Ничего интересного не должно быть в скрипте FastCGI. Вам не нужно тесно связывать все приложения с тем, что его активирует.

Возможно, вы захотите посмотреть мою главу о модулях в Мастеринг Perl , чтобы увидеть, как вы можете превратить ваши скрипты в модули многократного использования. Подобные вещи делают такие вещи действительно легкими.

Для постоянных соединений с базой данных у вас есть немного больше работы. Вы можете установить соединение вне цикла, но периодически вам нужно пропинговать его и, возможно, восстановить. Посмотрите, что Apache :: DBI для этого.

0 голосов
/ 21 ноября 2009

Подзапрос C: (постоянные соединения с БД)

Взгляните на DBI-> connect_cached () . Я полагаю, что вы можете использовать его внутри вашего цикла CGI :: Fast, и DBI.pm запомнит / кеширует ваше соединение. Таким образом, при 2-м, 3-м и т. Д. Вызовах connect_cached () с теми же параметрами вы получите существующее соединение. Он создаст новое соединение, если старое больше не доступно.

Что действительно хорошо в этом подходе, так это то, что единственное изменение, которое вы должны внести в существующее приложение (кроме добавления цикла CGI :: Fast), это заменить connect () на connect_cached (). А connect_cached () тоже будет работать с простым ванильным CGI.

См. Также Нужно ли размещать соединение / инициализацию БД вне цикла FCGI, чтобы использовать FastCGI в Perl? а также http://www.mail-archive.com/cgiapp@lists.erlbaum.net/msg04351.html

...