Async-Event-Interval

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

    - Fixes #16; _rand_shm_lock() now returns 1 + ($$ % 32767) so the value
      fits in IPC::Shareable 1.14+'s SEM_PROTECTED semaphore slot
    - shared_scalar() segments are now tied with protected => _shm_lock() to
      close the IPC::Shareable->clean_up_all foot-gun that could wipe them
      out from under a running event; the owning event's DESTROY still
      removes them via IPC::Shareable->remove
    - %events bootstrap loop is now capped at SHM_CREATE_RETRIES (100)
      attempts and croaks with the last underlying error instead of
      spinning forever when shmget fails persistently
    - All reads/writes to %events now go through _events_read (LOCK_SH) /
      _events_write (LOCK_EX) to synchronize access across processes
    - events() now returns a read-locked deep copy snapshot; mutations to
      the returned hashref do not affect the live %events
    - info() now returns a shallow copy snapshot, consistent with events()
    - _rand_shm_key() now generates hex strings within the 32-bit SHM key
      range (0x0–0x7FFFFFFF), replacing the 12 random letters which also
      removes the srand()-in-a-loop pattern
    - shared_scalar() no longer stores tied refs inside %events;
      %events now holds an arrayref of hex key strings instead,
      eliminating a same-process FETCH deadlock in IPC::Shareable
    - $SIG{__WARN__} moved to local inside _event() so it no longer

META.json  view on Meta::CPAN

{
   "abstract" : "Scheduled and one-off restartable asynchronous events",
   "author" : [
      "Steve Bertrand <steveb@cpan.org>"
   ],
   "dynamic_config" : 1,
   "generated_by" : "ExtUtils::MakeMaker version 7.64, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",

META.yml  view on Meta::CPAN

---
abstract: 'Scheduled and one-off restartable asynchronous events'
author:
  - 'Steve Bertrand <steveb@cpan.org>'
build_requires:
  File::Temp: '0'
  Mock::Sub: '0'
  Test::More: '0'
  Test::SharedFork: '0'
configure_requires:
  ExtUtils::MakeMaker: '0'
dynamic_config: 1

lib/Async/Event/Interval.pm  view on Meta::CPAN

}

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;

lib/Async/Event/Interval.pm  view on Meta::CPAN

    }

    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.

t/05-base.t  view on Meta::CPAN


my $mod = 'Async::Event::Interval';

my $file = 't/test.data';

{
    my $e = $mod->new(0.2, \&perform, 10);

    $e->start;

    is -e $file, undef, "event is asynchronious";

    sleep 2;

    $e->stop;

    my $data;

    {
        local $/;
        open my $fh, '<', $file or die $!;

t/20-restart.t  view on Meta::CPAN


my $mod = 'Async::Event::Interval';

my $file = 't/test.data';

{
    my $e = $mod->new(0.2, \&perform, 10);

    $e->restart;

    is -e $file, undef, "event is asynchronious";

    sleep 2;

    $e->stop;

    my $data;
    {
        local $/;
        open my $fh, '<', $file or die $!;
        $data = <$fh>;

t/61-error_and_waiting_fields.t  view on Meta::CPAN

use lib 't/lib';
use TestHelper;
use Test::More;
use Time::HiRes ();

use Async::Event::Interval;

my $mod = 'Async::Event::Interval';

# Poll-until-condition with a wall-clock deadline. Replaces fixed select()
# sleeps in blocks that wait for an asynchronous state transition (callback
# crash registers, restart clears flag, etc.) so the tests are robust on
# slow VMs without inflating wall-clock on healthy runs. Returns 1 on
# condition met, 0 on deadline hit.

sub poll_until {
    my ($cond, $timeout) = @_;
    $timeout //= 5;
    my $deadline = Time::HiRes::time() + $timeout;
    while (! $cond->()) {
        return 0 if Time::HiRes::time() >= $deadline;



( run in 2.294 seconds using v1.01-cache-2.11-cpan-9581c071862 )