Хорошо, так что я в тупике. Вот что я, похоже, не могу решить: при вызове общедоступного API первое, что требуется, это токен доступа - позвоним мне мой метод get_access_token(). Как только я получаю токен доступа, я буду использовать его для получения данных из публичного API. Теперь токен истекает через определенное количество секунд, причем этот номер снабжен токеном доступа. Итак, идея состоит в том, чтобы настроить какой-то таймер, который обновит токен доступа, вызвав get_access_token() снова, как только предыдущий токен истечет, так что я могу продолжать получать данные из API, всегда с допустимым токеном доступа.Perl: многократно вызывает подпрограмму после (возможно меняющейся) задержки времени
Я попытался с помощью:
- сигнализация
- AnyEvent
- Время :: HiRes-КЯ (setitimer ITIMER_VIRTUAL время)
Но я не могу получить любой из них в Работа. Я не привязан к какому-либо конкретному подходу; Я знаю, что могу решить эту проблему с помощью простой «проверки каждый так часто, чтобы узнать, истекает ли токен доступа», используя time() и арифметику, но я подумал, что попробую что-то более сложное. Очевидно, слишком сложный для меня!
Да, я знаю, что обычно один код сообщения, но, очевидно, мой код - все дерьмо, поэтому я просто ищу некоторые указатели о том, как лучше всего подойти к этому конкретному варианту использования. Любая помощь будет оценена по достоинству.
Редактировать
Для @ThisSuitIsBlackNot, вот тест сигнала (не фактические вызовов API не сделали). Авария срабатывает один раз, но никогда больше:
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
use Time::HiRes;
my $timeout = 7;
my $counter = 0;
my $rv = wrapper();
say $rv;
exit;
### subroutines
sub getAccessToken {
return localtime(time());
}
sub getSomeIDs {
my $accessToken = shift;
say "getting IDs: timeout == $timeout";
eval {
local $SIG{'ALRM'} = sub { wrapper(); };
alarm($timeout);
while (1) {
if ($counter == 25) { return; }
say "[ $accessToken ] $counter";
$counter = $counter + 1;
alarm_resistant_sleep(1);
}
alarm(0);
};
alarm(0);
return "counter at $counter";
}
sub wrapper {
my $at = getAccessToken();
return getSomeIDs($at);
}
sub alarm_resistant_sleep {
my $end = Time::HiRes::time() + shift();
for (;;) {
my $delta = $end - Time::HiRes::time();
last if $delta <= 0;
select(undef, undef, undef, $delta);
}
}
И вот попытка использования AnyEvent. Изначально я не использовал закрывающий вещь, но читать еще один пост, который предложил делать так (до сих пор не работает):
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
use AnyEvent;
my $accessToken;
my $timeout = 7;
my $cv = AE::cv;
my $counter = 0;
my $f1 = makeClosure(\&refreshAccessToken);
my $f2 = makeClosure(\&getSomeIDs);
$f1->();
$f2->();
$cv->recv();
exit;
### subroutines
sub makeClosure {
my $sub = shift;
return $sub;
}
sub getAccessToken {
$accessToken = localtime(time());
}
sub refreshAccessToken {
my $t1; $t1 = AE::timer 0, $timeout,
sub {
say "callback called";
$timeout--;
$accessToken = localtime(time());
#getAccessToken();
undef $t1;
};
say "calling refreshAccessToken()";
}
sub getSomeIDs {
my $t2; $t2 = AE::timer 0, 1,
sub {
if ($counter >= 16) { undef $t2; }
say "[ $accessToken ] $counter";
$counter = $counter + 1;
};
say "getting IDs: timeout == $timeout";
}
И, наконец, вот тест Time::HiRes
. Опять же, этот код прошел множество модификаций, пытаясь заставить его работать. Смешное значение проверяется на $counter
было просто, чтобы увидеть, если таймер был вызван в любой момент, что это не было:
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
use Time::HiRes qw(setitimer ITIMER_VIRTUAL time);
my $accessToken;
my $counter = 0;
$SIG{VTALRM} = \&refreshAccessToken;
setitimer(ITIMER_VIRTUAL, 1, 5);
Time::HiRes::sleep(2);
getAccessToken();
getSomeIDs();
exit;
### subroutines
sub refreshAccessToken {
my $timeout = getAccessToken();
local $SIG{VTALRM} = \&refreshAccessToken;
setitimer(ITIMER_VIRTUAL, $timeout, $timeout);
die;
}
sub getAccessToken {
say "getting access token";
$accessToken = localtime(time());
return 2;
}
sub getSomeIDs {
my $loop = 1;
#say "getting IDs: timeout == $timeout";
while ($loop) {
if ($counter >= 1600000000) { $loop = 0; }
say "[ $accessToken ] $counter";
$counter = $counter + 1;
};
}
Вы только позвоните 'тревоги ($ таймаут),' один раз, так что тревога срабатывает только один раз. Вы должны вызывать его каждый раз, когда вы получаете новый токен доступа. – ThisSuitIsBlackNot
Я думал, что он будет вызван несколько раз, потому что '$ SIG {ALRM}' установлен для вызова подпрограммы 'wrapper()', которая включает вызов 'getSomeIDs()', который вызывает 'alarm ($ timeout)'. – rwatkins
Я просто попытался добавить 'alarm ($ timeout)' в 'getAccessToken()' подпрограмму - он не изменил поведение в малейшей степени. – rwatkins