Есть мдуль DBD::Oracle для работы с базой данных Oracle. В этом модуле нет опции настройки таймаута при работе с базой.Так же есть решение, описанное тут http://search.cpan.org/~lbaxter/Sys-SigAction/dbd-oracle-tim..., которое позволяет решить проблему. Но при этом приходится каждый раз при вызове любого метода обращения к базе (connect, prepare, execute, do и т.д.) "заворачивать" его в громоздкую "обертку" с обработкой сигналов, как это описано в методе.
Что хочется.
Создать прослойку (дочерний класс для DBD::Oracle), в котором один раз описать все эти методы обращения к базе с "оберткой" и уже в коде основной программы использовать этот дочерний класс.
Как это сделать?P.S. С классами в Perl я на "Вы" по большей части,- от этого такой вопрос.
>Есть мдуль DBD::Oracle для работы с базой данных Oracle. В этом модуле
>нет опции настройки таймаута при работе с базой.
>
>Так же есть решение, описанное тут http://search.cpan.org/~lbaxter/Sys-SigAction/dbd-oracle-tim..., которое позволяет решить проблему. Номожно конечно и классами, но вот посмотри, правда тут много лишнего но ведь это тест:
--------------------------------------------------------------------------------------
#!/usr/bin/perl -wuse strict;
use Data::Dumper;sub safetimeout {
my ($action_ref, $param_ref, $timeoutaction_ref, $timeout_param_ref, $timeout) = @_;
my $result_ref;
undef($@);
eval {
#print "set timeout action: $timeoutaction_ref with param:\n";
#print Dumper($timeout_param_ref)."\n";
local $SIG{ALRM} = sub { &$timeoutaction_ref(@$$timeout_param_ref); };
print "set timeout: $timeout sec .\n";
alarm($timeout); #implement N second time out
#print "call: $action_ref with param:\n";
#print Dumper($param_ref)."\n";
$result_ref = \&$action_ref( @$$param_ref);
#\&$action_ref( @$param_ref);
alarm(0);
};
alarm(0);
if ( $@ ) { print "execute timed out or error: $@\n" }
if(defined($result_ref) ) {
if(ref($result_ref) eq 'ARRAY') {
return @$result_ref;
} elsif (ref($result_ref) eq 'SCALAR'){
return $$result_ref;
} else {
return $result_ref;
}
} else {
print "undefined result!\n";
}
}
sub act_test1 {
my @arg_list = @_;
print "test1: start short operation\n";
print "get argument list\n";
print Dumper(@arg_list);
print "test1: end short operation\n";
return 'for test1_return';
}sub timeout_test1 {
my @arg_list = @_;
print "TIMEOUT!!! operation test!!";
print "get argument list\n";
print Dumper(@arg_list)."\n";
return "ret from timeout";
}sub test1 {
print "start test 1!\n";
print "call timeout safe procedure!\n";
my $ret = safetimeout(\&act_test1, \['param1', 'p2', 'p3'], \&timeout_test1, \["timeout param1"], 2);
print "return resultis:\n";
print Dumper($ret);print "end test 1!\n";
}
sub act_test2 {
my @arg_list = @_;
print "test2: start long operation\n";
print "get argument list\n";
print Dumper(@arg_list);
my $time_sleep = $arg_list[0] || 1;
print "start sleeping: $time_sleep sec.\n";
sleep $time_sleep;
print "end sleeping\n";
print "test2: end operation\n";
return ['for test2_return', 1, 3, 'ret test2'];
}
sub test2 {
print "start test 2!\n";
print "call timeout safe procedure!\n";
my $ret = safetimeout(\&act_test2, \[5, 'p2', 'p3'], \&timeout_test1, \["timeout param1"], 2);
print "return resultis:\n";
print Dumper($ret);print "end test 2!\n";
}sub test2_1 {
print "start test 2_1!\n";
print "call timeout safe procedure!\n";
my @ret = safetimeout(\&act_test2, \[5, 'p2', 'p3'], \&timeout_test1, \["timeout param1"], 7);
print "return resultis:\n";
print Dumper(@ret);print "end test 2_1!\n";
}
print "--------------------------------------------------\n";
&test1();
&test2();
&test2_1();
exit(0);
----------------------------------------------------------
все зависающие операции можно вызывать через оболочку:
safetimeout(), передав саму операцию, аргументы, можно еще и обработчик таймаутов, да и само время тайм аута.поскольку здесь мы имеем дело с объектами, можно в параметре предать объект, а в фукции защищаемой функции вызвать необходимый метод, и передать туда необходимые аргументы,
всего таких фукций надо написать по числу защищаемых методов. но зато исходный код пострадает не сильно. хотя не знаю может быть можно как нибудь еще и имя метода передать, чтобы не писать кучу функций, надо подумать.
>>Есть мдуль DBD::Oracle для работы с базой данных Oracle. В этом модуле
>>нет опции настройки таймаута при работе с базой.
>>
>>Так же есть решение, описанное тут http://search.cpan.org/~lbaxter/Sys-SigAction/dbd-oracle-tim..., которое позволяет решить проблему. Но
>
>всего таких фукций надо написать по числу защищаемых методов. но зато исходный
>код пострадает не сильно. хотя не знаю может быть можно как
>нибудь еще и имя метода передать, чтобы не писать кучу функций,
>надо подумать.в принципе я сделал и для объектов, так же рабоатет правда вот определения адреса метода у меня немного по дурацки получилось, т.е явное указание файла объекта.:
my $ret = safetimeout($a, \&myObj::getdata, \['param2'], \&timeout_test1, \["timeout param1"], 3);ну и вызов его в safetime:
$result_ref = $obj->$action_ref( @$$param_ref);
>[оверквотинг удален]
>>>нет опции настройки таймаута при работе с базой.
>>>
>>>Так же есть решение, описанное тут http://search.cpan.org/~lbaxter/Sys-SigAction/dbd-oracle-tim..., которое позволяет решить проблему. Но
>>
>>всего таких фукций надо написать по числу защищаемых методов. но зато исходный
>>код пострадает не сильно. хотя не знаю может быть можно как
>>нибудь еще и имя метода передать, чтобы не писать кучу функций,
>>надо подумать.
>
>в принципе я сделал и для объектов, так же рабоатет правда вотвот сделал с использованием символических ссылок, они выглядят более красиво:
вызов:
my $ret = safetimeout($a, 'getdata', \['param2'], \&timeout_test1, \["timeout param1"], 3);использование: в safetimeout
sub safetimeout {
my ($obj, $action_symref, $param_ref, $timeoutaction_ref, $timeout_param_ref, $timeout) = @_;
my $result_ref;
undef($@);
eval {
local $SIG{ALRM} = sub { &$timeoutaction_ref(@$$timeout_param_ref); };
print "set timeout: $timeout sec .\n";
alarm($timeout); #implement N second time out
$result_ref = $obj->$action_symref( @$$param_ref);
....
>[оверквотинг удален]
> undef($@);
> eval {
> local $SIG{ALRM} = sub { &$timeoutaction_ref(@$$timeout_param_ref);
>};
> print "set timeout: $timeout sec .\n";
>
> alarm($timeout); #implement N second time out
>
> $result_ref = $obj->$action_symref( @$$param_ref);
>....у меня немного другая задумка была - так примерно:
в DBI есть, например, функции do, prepare и execute
есть так же функция errstr, в которая возвращает текст возникающих ошибокт.е. я создаю класс и делаю запрос:
####### подключаюсь к серверу
my $db = DBI->new( 'DBI:mysql:database=base;host=host', $user, $psaaword );####### пусть тут у меня неожиднно пропадает коннект к базе
####### где-то маршрутизатор сломался, например
sleep 5;####### вот эта функция не выполнится о-о-очень долго из-за потери связи
####### она должна быть "обернута в таймаут уловитель"
my $res = $db->do( 'SELECT * FROM duel' );unless( $res ) {
print $db->errstr;
}вот как бы сделать так, чтобы я по прежнему мог использовать do функцию DBI модуля без всяческих ухищрений, а если будет ошибка по таймауту, то эта ошибка так же будет в доступна через errstr?
т.е. я так понимаю, что нужно унаследовать DBI класс и перегрузить все функции - do, prepare и execute - так, что бы они работали через "таймаут уловитель", т.е. что то типа этого:package MyDBI;
use DBI;
### тут перегрузить все функци, что мне нужны
sub do {
## оборачиваю родительскую функцию в "таймаут уловитель"
}sub errstr {
## если будет таймаут, то эта функция будет возвращать текст ошибки таймаута
}package main;
# использую MyDBI вместо DBI
my $db = MyDBI->new( 'DBI:mysql:database=base;host=host', $user, $psaaword );
sleep 5;
my $res = $db->do( 'SELECT * FROM duel' );
unless( $res ) {
print $db->errstr;
}не хватает знаний по классам, что бы такую штуку сделать...
Да я понял чего ты хочешь сделать. я бы не стал уж больно муторно, потом еще отлаживать заколебешся.
>####### подключаюсь к серверу
>my $db = DBI->new( 'DBI:mysql:database=base;host=host', $user, $psaaword );
>
>####### вот эта функция не выполнится о-о-очень долго из-за потери связи
>####### она должна быть "обернута в таймаут уловитель"
>my $res = $db->do( 'SELECT * FROM duel' );пото до и ехекут вообще разным классам принадлежат.
my $timeouterr;
вот пользуй синтаксис:
в safetimeout
undef $timeoutstr;
а в timeout_proc ее присваивай.
my $ret = safetimeout($db, 'do', \['SELECT * FROM duel'], \&timeout_proc, \[], 3);
if(defined($timeoutstr)) {
....
}и вообще каждую операцию не обязательно в тайм аут брать выдели всю транзакцию в и защити ее по тайм ауту. те и подключение и несколько обновлений.
>и вообще каждую операцию не обязательно в тайм аут брать выдели всю
>транзакцию в и защити ее по тайм ауту. те и подключение
>и несколько обновлений.да, так и сделаю
спасибо! :)