2010-10-31 4 views
0

Я использую CentOS 5.5 Linux (такой же, как Redhat 5.5) с запасом perl v5.8.8 и установил DBD-Pg-2.17 .1 через оболочку CPAN, и я использую postgresql-server-8.4.5-1PGDG.rhel5 и друзей.Асинхронные запросы с DBD :: Pg сбой: невозможно выполнить, пока предыдущий запрос async не завершился

Я подготовил простой тестовый пример, демонстрирующий . Проблема моя - это указано внизу.

Мой код работает нормально, когда я удалить {pg_async => PG_ASYNC}

Мой фон является то, что у меня есть небольшая Facebook игра работает как не запускающим Unix демон с IO :: Poll. Я хотел бы добавить некоторые статистические данные для игроков, , но я не хочу, чтобы задушить мою подушную петлю, так что я бы хотел отправить в основном INSERT/UPDATE команды asynchronously и не нужен никакие возвращений значения из базы данных - потому что для чтения/отображения статистики У меня будут отдельные веб-скрипты.

Удивительно, я получаю сообщение об ошибке DBD :: Pg :: ул выполнить не удалось: не удалось выполнить до предыдущего запроса асинхронной не закончил, даже если я не использую PG_OLDQUERY_WAIT

Вот мой код (Мой демон должен восстановить к PostgreSQL, когда соединение потеряно, , поэтому я использую * _cached методы и не выйти на Eval {....} исключений):

#!/usr/bin/perl -w 

use strict; 
use DBI; 
use DBD::Pg qw(:async); 

use constant DBNAME => 'snake'; 
use constant DBUSER => 'snake'; 
use constant DBPASS => 'snake'; 

use constant SQL_CREATE_TABLES => q{ 
     /* 
     create table pref_users (
       id varchar(32) primary key, 
       first_name varchar(32), 
       last_name varchar(32), 
       female boolean, 
       avatar varchar(128), 
       city varchar(32), 
       lat real check (-90 <= lat and lat <= 90), 
       lng real check (-90 <= lng and lng <= 90), 
       last_login timestamp default current_timestamp, 
       last_ip inet, 
       medals smallint check (medals > 0) 
     ); 

     create table pref_rate (
       obj varchar(32) references pref_users(id), 
       subj varchar(32) references pref_users(id), 
       good boolean, 
       fair boolean, 
       nice boolean, 
       about varchar(256), 
       last_rated timestamp default current_timestamp 
     ); 

     create table pref_money (
       id varchar(32) references pref_users, 
       yw char(7) default to_char(current_timestamp, 'YYYY-WW'), 
       money real 
     ); 
     create index pref_money_yw_index on pref_money(yw); 

     create table pref_pass (
       id varchar(32) references pref_users 
     ); 

     create table pref_misere (
       id varchar(32) references pref_users 
     ); 
     */ 

     create or replace function pref_update_users(_id varchar, 
      _first_name varchar, _last_name varchar, _female boolean, 
      _avatar varchar, _city varchar, _last_ip inet) returns void as $BODY$ 
       begin 

       update pref_users set 
        first_name = _first_name, 
        last_name = _last_name, 
        female = _female, 
        avatar = _avatar, 
        city = _city, 
        last_ip = _last_ip 
       where id = _id; 

       if not found then 
         insert into pref_users(id, first_name, 
          last_name, female, avatar, city, last_ip) 
         values (_id, _first_name, _last_name, 
          _female, _avatar, _city, _last_ip); 
       end if; 
       end; 
     $BODY$ language plpgsql; 
}; 

eval { 
     my $dbh = DBI->connect_cached('dbi:Pg:dbname=' . 
      DBNAME, DBUSER, DBPASS, { 
      AutoCommit => 1, 
      PrintWarn => 1, 
      PrintError => 1, 
      RaiseError => 1, 
      FetchHashKeyName => 'NAME_lc', 
      pg_enable_utf8 => 1 
     }, {pg_async => PG_ASYNC}); 

     $dbh->do(SQL_CREATE_TABLES, {pg_async => PG_ASYNC}); 
}; 
warn [email protected] if [email protected]; 

for my $i (1..10) { 
     eval { 
       my $dbh = DBI->connect_cached('dbi:Pg:dbname=' . 
        DBNAME, DBUSER, DBPASS, { 
        AutoCommit => 1, 
        PrintWarn => 1, 
        PrintError => 1, 
        RaiseError => 1, 
        FetchHashKeyName => 'NAME_lc', 
        pg_enable_utf8 => 1 
       }, {pg_async => PG_ASYNC}); 

       #$dbh->pg_result; 

       my $sth = $dbh->prepare_cached(
        q{select pref_update_users(?, ?, ?, ?, ?, ?, NULL)}, {pg_async => PG_ASYNC}); 

       $sth->execute('ID123', 'Alexander', 'Farber', undef, undef, undef); 
     }; 
     warn [email protected] if [email protected]; 
} 

Спасибо, Alex

+1

делает 'предупреждение $ @ if $ @' после 'eval {};' блок упоминает что-нибудь? Почему вы уже не проверяете ошибки eval? – mfontani

+0

Здравствуйте, "warn $ @ if $ @;" печатает точно такую ​​же строку как PrintError, поэтому я опустил его. –

+0

Я добавил предупреждение в мой код @ и прокомментировал создание таблицы, но это не действительно меняют что-то здесь. –

ответ

2

DBD :: Pg асинхронная поддержка работает, как, что, только один активный асинхронный запрос в то время. Константы PG_OLDQUERY_CANCEL и PG_OLDQUERY_WAIT должны быть установлены, если вы хотите отменить или дождаться текущего активного запроса, а затем выполнить новый запрос, а не бросать ошибку о старых запросах.

Вы можете добавить свои запросы в AoH (массив хашей) или Thread::Queue (игнорировать имя, оно полезно как общий объект очереди и выполнять их по таймеру (после того, как предыдущий завершен) (или добавить сокет $ dbh -> {pg_socket} в ваши опросные сокеты с IO :: Poll и проверить готовность вашего запроса и выполнить следующий запрос в вашей очереди, когда этот сокет имеет данные для чтения, что указывает на то же, что и pg_ready).