[Moscow.pm] Неблокирующий клиент к Redis Cluster

Eugene Ponizovsky ponizovsky на gmail.com
Чт Сен 22 05:36:00 PDT 2016


> 22 сент. 2016 г., в 12:39, Ruslan Zakirov <ruslan.zakirov на gmail.com> написал(а):
> 
> 
> 2016-09-22 11:16 GMT+03:00 Eugene Ponizovsky <ponizovsky на gmail.com <mailto:ponizovsky на gmail.com>>:
> Руслан, если я правильно все рассчитал, то этот callback не будет вызван, если не осталось ни одной нормальной ссылки на $self, так как сам callback помещается в $self далее по коду, и он будет уничтожен вместе с последней ссылкой на объект клиента. Есть ли у Вас пример, в котором это приводит к ошибке?
> 
> Возможно вы правы. Это были домыслы на основе чтения кода.
> 
> Вот натолкнулся на более актуальную проблему и это уже в тестах:
> EV: error in callback (ignoring): Can't call method "_process_reply" on an undefined value at /Users/ruz/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/AnyEvent/RipeRedis.pm line 448, <DATA> line 2231.
> 
Хм. Да, действительно. При некоторых случаях ошибка воспроизводится. Внес небольшой фикс. Спасибо за репорт.
https://cpan.metacpan.org/authors/id/I/IP/IPH/AnyEvent-RipeRedis-0.27_01.tar.gz

> Это как раз случилось из-за того что клиент прибиваю раньше времени. Ошибка конечно у меня, но она не привела к "Client object destroyed prematurely."
> 
> Кстати как вы это решаете у себя? Я в большинстве случаев создаю коннект, выполняю ряд операций без callback'а и только на после последней передаю callback, где резолвлю promise (дергаю переданный callback). В некоторых случаях совсем нетривиально подсчитать какая команда будет последней.
> 

Если выполнять простые операции (get, set, incr и т.д.), то последовательность их выполнения совпадает с последовательностью вызова методов в коде, так как они все выполняются через один коннект. Но для составных операций (например для такой как eval_cached), последовательность выполнения может быть другой, так как под капотом может быть выполнено две команды EVALSHA и следом EVAL.

В общем случае синхронизировать асинхронные операции можно через счетчик операций. Например так:

my $oprn_num  = 10; 
my $reply_cnt = $oprn_num;
my @errors;

my $cv = AE::cv;

my $cb = sub {
  my $reply = shift;
  my $err   = shift;

  if ( defined $err ) { 
    push( @errors, $err );
  }

  return if --$reply_cnt > 0;
  
  if ( @errors ) { 
    # обработка ошибок
  }
  else {
    # выполняем код, который нужно выполнить, когда все асинхронные операции
    # успешно выполнены.
  }

  $cv->send;
};

foreach ( 1 .. $oprn_num ) { 
  $client->execute( $cb );
}

$cv->recv;

Или воспользоваться таким модулем как Future https://metacpan.org/pod/Future

> -- 
> Best regards, Ruslan.
> -- 
> Moscow.pm mailing list
> moscow-pm на pm.org | http://moscow.pm.org

----------- следущая часть -----------
Вложение в формате HTML было извлечено…
URL: <http://mail.pm.org/pipermail/moscow-pm/attachments/20160922/8cbc36bb/attachment-0001.html>


Подробная информация о списке рассылки Moscow-pm