Okay, so I'm stumped. Here's the thing I can't seem to solve: In making calls a public API, the first thing required is an access token -- let's call my method get_access_token(). Once I've got the access token I will use it to get data from the public API. Now, the token expires after a certain number of seconds, that number being provided with the access token. So, the idea is to set up some sort of timer that will refresh the access token by calling get_access_token() again once the previous token expires, so that I can continue to get data from the API, always with a valid access token.
I've tried using:
- alarm
- AnyEvent
- Time::HiRes qw(setitimer ITIMER_VIRTUAL time)
But I can't get any of these to work. I'm not wedded to any particular approach; I know I could solve it with a simple "check every so often to see if the access token is about to expire" using time() and arithmetic, but I thought I'd try something a little more sophisticated. Evidently too sophisticated for me!
Yes, I know that usually one posts code, but obviously my code is all crap, so really I'm just looking for some pointers about how best to approach this particular use case. Any help would be appreciated.
Edit
For @ThisSuitIsBlackNot, here's the alarm test (no actual API calls made). The alarm fires once but never again:
#!/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);
}
}
And here's the attempt to use AnyEvent. Originally I didn't use the closure thing, but read another post that suggested doing so (still didn't work):
#!/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";
}
And, finally, here's the Time::HiRes test. Again, this code went through many modifications trying to get it to work. The ridiculous value tested against $counter was simply to see if the timer was called at any point, which it was not:
#!/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;
};
}
alarm($timeout);once, so the alarm only fires once. You need to call it every time you get a new access token.$SIG{ALRM}is set to call thewrapper()subroutine, which includes a call togetSomeIDs(), which callsalarm($timeout).alarm($timeout)in thegetAccessToken()subroutine -- it did not change the behaviour in the slightest.