Async-Event-Interval
view release on metacpan or search on metacpan
lib/Async/Event/Interval.pm view on Meta::CPAN
warn $msg;
};
IPC::Shareable::clean_up_protected(_shm_lock());
});
}
sub DESTROY {
my $self = $_[0];
return if $$ != $creator_pid;
return if $_shutting_down;
if (defined $self) {
$self->stop if $self->pid;
}
# On events with interval of zero, ForkManager runs finish(), which calls
# our destroy method. We only want to blow away the %events hash if we truly
# go out of scope
return if (caller())[0] eq 'Parallel::ForkManager::Child';
# Release any shared_scalar segments owned by this event. These are tracked
# in $self->{_shared_scalars}, not inside %events, so they can be cleaned up
# outside the %events lock.
if ($self->{_shared_scalars}) {
for my $scalar (@{ $self->{_shared_scalars} }) {
next unless ref $scalar eq 'SCALAR';
my $knot = tied $$scalar;
eval { $knot->remove } if $knot;
}
}
my $ok = eval {
_events_write(sub {
delete $events{$self->id};
$events{_event_count}--;
});
1;
};
if (! $ok) {
if (my $knot = tied(%events)) {
$knot->{_lock} = 0;
}
}
}
END {
_end(1);
}
sub _vim{} # vim navigation marker; intentionally empty
1;
__END__
=head1 NAME
Async::Event::Interval - Scheduled and one-off restartable asynchronous events
=for html
<a href="https://github.com/stevieb9/async-event-interval/actions"><img src="https://github.com/stevieb9/async-event-interval/workflows/CI/badge.svg"/></a>
<a href='https://coveralls.io/github/stevieb9/async-event-interval?branch=master'><img src='https://coveralls.io/repos/stevieb9/async-event-interval/badge.svg?branch=master&service=github' alt='Coverage Status' /></a>
=head1 SYNOPSIS
Here's an example of a simple asynchronous event that fetches JSON data from a
website every two seconds using a shared scalar variable to hold the decoded
JSON hashref, while allowing the main application to continue running in the
foreground. Multiple events can be used simultaneously if desired.
See the L</SCENARIOS/EXAMPLES> section for further usage examples.
use warnings;
use strict;
use Async::Event::Interval;
use JSON;
my $event = Async::Event::Interval->new(2, \&callback);
my $api_data_href = $event->shared_scalar;
$event->start;
while (1) {
if ($$api_data_href) {
print "Element 1 of 'data' dict is $$api_data_href->{data}[1]\n";
# ...do other things with data
}
# ...do other things
if ($event->error) {
print $event->error_message;
$event->restart;
}
}
sub callback {
my $api_json = some_web_api_call(); # '{"data": [1, 2, 3]}';
$$api_data_href = decode_json($api_json);
}
=head1 DESCRIPTION
Very basic implementation of asynchronous events triggered by a timed interval.
If a time of zero is specified, we'll run the event only once while providing
the ability to re-run it manually at any time in the future.
B<Signal handling>: The module installs C<$SIG{INT}> and C<$SIG{TERM}>
handlers at load time to ensure shared memory segments are cleaned up when the
host process is killed by a signal. The handlers stop any running event
children, remove all shared memory segments, then re-raise the signal with the
default handler so the process exits with the correct status. If you install
your own handlers for these signals, call C<Async::Event::Interval::_end(1)>
from them before exiting to avoid leaking segments.
The module also sets C<$SIG{CHLD} = 'IGNORE'> at load time to automatically
reap forked event children, preventing zombie processes. If you need to
manage child processes manually (e.g. to call C<waitpid> yourself), install
your own C<$SIG{CHLD}> handler after C<use Async::Event::Interval>.
=head1 METHODS - EVENT OPERATION
=head2 new($delay, $callback, @params)
Returns a new C<Async::Event::Interval> object. Does not start the event. Use
L<start()|/start(@params)> for that.
Parameters:
$delay
Mandatory: The interval on which to trigger your event callback, in seconds.
Represent partial seconds as a floating point number. If zero is specified,
we'll simply run the event once and stop.
$callback
Mandatory: A reference to a subroutine that will be called every time the
interval expires.
@params
Optional, List: A list of parameters to pass to the callback. Note that these
are not shared parameters and are a copy only, so changes to them in the main
code will not be seen in the event, and vice-versa. See L</shared_scalar> if
you'd like to use variables that can be shared between the main application and
the events.
These parameters are sent into the event only once. Each time the callback is
called, they will receive the exact same set of params.
To have the event get different values in the params each time the callback is
called, see L<start()|/start(@params)>.
B<Note>: You can set a per-callback-execution timeout via
L<timeout()|/timeout($seconds)> before calling C<start()> to have the event
terminate itself if a callback runs longer than the specified number of seconds.
B<Note>: You can set L<immediate()|/immediate($value)> to have the callback fire
immediately on C<start()>, rather than waiting for the first interval.
=head2 start(@params)
Starts the event timer. Each time the interval is reached, the event callback
( run in 2.504 seconds using v1.01-cache-2.11-cpan-9581c071862 )