in reply to IO::Async::Loop in multiple modules all loaded

In general, you only want a single event loop. Most event loop modules solve this by having a singleton event loop that gets initialized on first use.

I can't really comment on your code and the sequence of your flow because you don't show it, but if the fetch() seems to come from ModuleA while you expect it to come from ModuleB, then that sounds to me as if you're mixing up things somewhere.

If you really want the fetch() from ModuleA and ModuleB to be executed sequentially, maybe launch them as

... my $dataA = await ModuleA->new()->give_me_data(); my $dataB = await ModuleB->new()->give_me_data(); ...

Replies are listed 'Best First'.
Re^2: IO::Async::Loop in multiple modules all loaded - code provided
by bliako (Abbot) on Feb 18, 2026 at 12:36 UTC

    I have now created a repository with example code and tests in order to play with websockets and IO::Async::Loop. It is located here/github,

    TL;DR: I can have a loop in each module. There does not seem to be a clash when all modules are fetch()ing which means there are instantiated loop object in each fetch() running, not a singleton.. Edit: Totally wrong, there is only one loop, a singleton and this is enforced internally by IO::Async::Loop.

    The only tiny problem I found is when fetching (i.e. running each module's fetch()) asynchronously with wait_all of Future. It does not run the last fetch() and it only returns just one result. Of course, the main culprit can be me.

    So, if anyone has time and knowledge, to upload the repo and run the tests and offer advice on:

    • Is running IO::Async::Loop loops from different modules safe and sound? It looks to me it is.
    • Why wait_all of Future as used in t/50-A-B-C-D-E-parallel.t does not work as I expect it?

    All in all, creating this repository was a good exercise but I am left with the same problems I posted although they do not appear in the test exercise at all. So, it makes me think that they can be because of communication glitches, running out of memory or other bugs. For example, in a server with little memory (6GB) and low CPU capacity, In either weak or strong servers I sometimes get one of these:

    • Too many fragments at .../site_perl/5.38.2/Protocol/WebSocket/Frame.pm line 232. Increasing the hardcoded max value seems to work (filed a bug/feature-request on this).
    • Can't call method "sysread" on an undefined value at ../site_perl/5.38.2/IO/Async/Stream.pm line ~985 (method _sysread). Basically it tries to read from stream but handle is undef. Perhaps because I tend to close the client and maybe prematurely. (note: edited this to be more accurate)

    Anyway, these problems do not appear in the test exercise, so my initial worry that multiple IO::Async::Loop objects somehow clash must be unfounded. I am now concentrating in how I send data to the socket, receive it, close the socket when had enough.

    Here is how I do it (the file lib/MY/A.pm in the provided repository):

    package MY::A; use strict; use warnings; use IO::Async::Loop; use Future; use Future::AsyncAwait; use Net::Async::WebSocket::Client; our $VERSION = '0.01'; sub new { my ($class, $params) = @_; $params //= {}; my $self = { 'max-hellos' => (exists($params->{'max-hellos'})&&defined($par +ams->{'max-hellos'})) ? $params->{'max-hellos'} : 4, 'websocket-uri' => (exists($params->{'websocket-uri'})&&define +d($params->{'websocket-uri'})) ? $params->{'websocket-uri'} : 'wss://echo.websocket.org', }; bless $self => $class; return $self; } async sub fetch { my ($self, $params) = @_; my $URI = $self->{'websocket-uri'}; my $MAX_HELLOS = $self->{'max-hellos'}; my $request = Protocol::WebSocket::Request->new( host => $URI, resource_name => __PACKAGE__ ); my $loop = IO::Async::Loop->new; my @data_received; my $num_items_received = 0; my $client = Net::Async::WebSocket::Client->new( on_text_frame => sub { my ( $clientself, $frame ) = @_; return unless $frame =~ /hello/; $num_items_received++; push @data_received, $frame; print __PACKAGE__." : on_text_frame() : got # ${num_items_rece +ived}: ${frame}\n"; # the 1st item is sent from the websocket like 'Request served + by 4d896d95b55478' # so we will save this but don't count it in the below test if( $num_items_received >= $MAX_HELLOS ){ print __PACKAGE__." : on_text_frame() : CLOSING client $cl +ientself.\n"; # we have received enough items, # stop the loop, is this the right way to do it? $loop->stop; $clientself->close_when_empty; # even if we stopped the loop, # data is kept added unless we return() here #return; } }, ); print __PACKAGE__." : adding client $client to the loop ...\n"; $loop->add( $client ); await eval { $client->connect( url => $URI, ) }; if( $@ ){ print STDERR __PACKAGE__." : failed to connect to URI '$ +{URI}'.\n"; return undef } # NOTE: $client will CLOSE after 4 items received # here we send 8 items, $client does not seem to be closed, # neither does $loop! for my $i (1..$MAX_HELLOS){ my $ts = "hello from ".__PACKAGE__." #${i}"; print __PACKAGE__." : sending data to socket : $ts\n"; $client->send_text_frame($ts); sleep(1); } $loop->run; #$client->close_when_empty if $client; #my $retdata = Future->done(\@data_received); #return $retdata; return \@data_received; } 1;

    thank you, bw bliako

      which means there are instantiated loop object in each fetch() running, not a singleton.

      That's not right. IO::Async::Loop->new returns a singleton.

      sub new { return our $ONE_TRUE_LOOP ||= shift->really_new; }

      That shouldn't be a problem, though. If your code is correct, it doesn't matter if multiple modules use the same loop.

        Thanks for the information, it was unclear to me.

        That shouldn't be a problem, though. If your code is correct, it doesn't matter if multiple modules use the same loop.

        Or too correct! As, I was doing a $loop->stop after closing the websocket.

      TL;DR: I can have a loop in each module

      Can't comment on anything else in your question, but doesn't this line contradict the above quote?

        yes, indeed after the answers to my question, including yours, I now realise that there is only one loop. Thank you.

Re^2: IO::Async::Loop in multiple modules all loaded
by bliako (Abbot) on Feb 19, 2026 at 22:32 UTC

    Thank you Corion. Despite what you said, I did not realise that the singleton loop is enforced by the module internally. So, the use of $loop->run and $loop->stop is not the right way when the singleton loop is used by many modules, hence my problems.