mojolicious / mojo-pg

Mojolicious :heart: PostgreSQL
https://metacpan.org/release/Mojo-Pg
Artistic License 2.0
101 stars 46 forks source link

Disconnections occur on PubSub, when EV is installed #70

Closed akarelas closed 3 years ago

akarelas commented 3 years ago

Steps to reproduce the behavior

When EV is installed and many (10 here) listening processes NOTIFY together at the same time, disconnections from the database occur very often (in this example, many disconnections per second).

The disconnects do not occur when running with MOJO_REACTOR=Mojo::Reactor::Poll.

use Mojo::Base -strict;

use Test::More;

use Mojo::IOLoop;
use Mojo::Pg;
use Time::HiRes 'time';

use constant DURATION => 2;

plan skip_all => 'set TEST_ONLINE to enable this test' unless $ENV{TEST_ONLINE};

my $total_disconnects = 0;

for (1 .. 10) {
  Mojo::IOLoop->subprocess->run_p(sub {
    my $t0              = time;
    my $me              = $$;
    my $num_disconnects = 0;
    my $pg              = Mojo::Pg->new($ENV{TEST_ONLINE});
    my $pubsub          = $pg->pubsub;
    $pubsub->reconnect_interval(0.01);
    $pubsub->on(
      disconnect => sub {

        # don't count any disconnects possibly caused by Mojo::IOLoop->reset
        $num_disconnects++ if $$ == $me and time < $t0 + 0.8 * DURATION;
      }
    );
    $pubsub->listen(events => sub { });
    Mojo::IOLoop->recurring(
      0.1 => sub {
        $pubsub->notify(events => 'foo');
      }
    );
    Mojo::IOLoop->timer(
      DURATION,
      sub {
        Mojo::IOLoop->reset;
      }
    );
    Mojo::IOLoop->start;
    return $num_disconnects;
  })->then(sub {
    $total_disconnects += $_[0];
  });
}

Mojo::IOLoop->start;

is $total_disconnects, 0, 'should not disconnect';

done_testing;

I had to make the unit test fork, because without forking the test would pass without errors.

Expected behavior

Output should be:

disconnects.t .. 
ok 1 - should not disconnect
1..1
ok
All tests successful.
Files=1, Tests=1,  3 wallclock secs ( 0.03 usr  0.01 sys +  0.46 cusr  0.11 csys =  0.61 CPU)
Result: PASS

Actual behavior

Output was (after two seconds):

disconnects.t .. 
not ok 1 - should not disconnect

#   Failed test 'should not disconnect'
#   at disconnects.t line 51.
#          got: '7'
#     expected: '0'
1..1
# Looks like you failed 1 test of 1.
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/1 subtests 

Test Summary Report
-------------------
disconnects.t (Wstat: 256 Tests: 1 Failed: 1)
  Failed test:  1
  Non-zero exit status: 1
Files=1, Tests=1,  2 wallclock secs ( 0.02 usr  0.01 sys +  0.43 cusr  0.14 csys =  0.60 CPU)
Result: FAIL
kraih commented 3 years ago

This is @jberger 's area, probably best if he takes a look first.

akarelas commented 3 years ago

Doing a binary search over commits of Mojo::Pg which fail or pass the above test, I found that the mojo-pg commit that breaks the above test is d51e252b157bc05928d92a85f1b92be23626d590 which resides between Mojo::Pg versions 4.13 and 4.14.

Everything after that breaks the test, whereas previous versions of Mojo::Pg pass the test.

akarelas commented 3 years ago

Also, the first version of Mojolicious that implemented subprocess's run_p method (v8.38), also failed the test when run against d51e252.

kraih commented 3 years ago

This seems to be a duplicate of #68.