Skip to content

Commit

Permalink
added next_tick method to Mojo::IOLoop and Mojo::Reactor
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Feb 26, 2014
1 parent e8cdca0 commit 245b93c
Show file tree
Hide file tree
Showing 16 changed files with 78 additions and 62 deletions.
1 change: 1 addition & 0 deletions Changes
@@ -1,5 +1,6 @@

4.85 2014-02-26
- Added next_tick method to Mojo::IOLoop and Mojo::Reactor.
- Improved Mojo::Reactor::EV responsiveness.

4.84 2014-02-22
Expand Down
24 changes: 18 additions & 6 deletions lib/Mojo/IOLoop.pm
Expand Up @@ -94,6 +94,7 @@ sub delay {
sub generate_port { Mojo::IOLoop::Server->generate_port }

sub is_running { _instance(shift)->reactor->is_running }
sub next_tick { _instance(shift)->reactor->next_tick(@_) }
sub one_tick { _instance(shift)->reactor->one_tick }

sub recurring { shift->_timer(recurring => @_) }
Expand Down Expand Up @@ -492,6 +493,23 @@ Check if event loop is running.
exit unless Mojo::IOLoop->is_running;
=head2 next_tick
my $undef = Mojo::IOLoop->next_tick(sub {...});
my $undef = $loop->next_tick(sub {...});
Invoke callback as soon as possible, but not before returning, always returns
C<undef>.
=head2 timer
my $id = Mojo::IOLoop->timer(5 => sub {...});
my $id = $loop->timer(5 => sub {...});
my $id = $loop->timer(0.25 => sub {...});
Create a new timer, invoking the callback after a given amount of time in
seconds.
=head2 one_tick
Mojo::IOLoop->one_tick;
Expand All @@ -513,9 +531,6 @@ into the reactor, so you need to be careful.
Create a new recurring timer, invoking the callback repeatedly after a given
amount of time in seconds.
# Invoke as soon as possible
Mojo::IOLoop->recurring(0 => sub { say 'Reactor tick.' });
=head2 remove
Mojo::IOLoop->remove($id);
Expand Down Expand Up @@ -593,9 +608,6 @@ Get L<Mojo::IOLoop::Stream> object for id or turn object into a connection.
Create a new timer, invoking the callback after a given amount of time in
seconds.
# Invoke as soon as possible
Mojo::IOLoop->timer(0 => sub { say 'Next tick.' });
=head1 DEBUGGING
You can set the MOJO_IOLOOP_DEBUG environment variable to get some advanced
Expand Down
5 changes: 2 additions & 3 deletions lib/Mojo/IOLoop/Client.pm
Expand Up @@ -29,14 +29,13 @@ sub connect {
my $self = shift;
my $args = ref $_[0] ? $_[0] : {@_};
weaken $self;
$self->{delay} = $self->reactor->timer(0 => sub { $self->_connect($args) });
$self->reactor->next_tick(sub { $self && $self->_connect($args) });
}

sub _cleanup {
my $self = shift;
return $self unless my $reactor = $self->reactor;
$self->{$_} && $reactor->remove(delete $self->{$_})
for qw(delay timer handle);
$self->{$_} && $reactor->remove(delete $self->{$_}) for qw(timer handle);
return $self;
}

Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/IOLoop/Delay.pm
Expand Up @@ -20,7 +20,7 @@ sub pass { $_[0]->begin->(@_) }

sub steps {
my $self = shift->remaining([@_]);
$self->ioloop->timer(0 => $self->begin);
$self->ioloop->next_tick($self->begin);
return $self;
}

Expand Down Expand Up @@ -51,7 +51,7 @@ sub _step {
}

return $self->emit(finish => @args) unless $self->{counter};
$self->ioloop->timer(0 => $self->begin) unless $self->{pending};
$self->ioloop->next_tick($self->begin) unless $self->{pending};
}

1;
Expand Down
30 changes: 17 additions & 13 deletions lib/Mojo/Reactor.pm
Expand Up @@ -27,13 +27,16 @@ sub is_readable {
}

sub is_running { croak 'Method "is_running" not implemented by subclass' }
sub one_tick { croak 'Method "one_tick" not implemented by subclass' }
sub recurring { croak 'Method "recurring" not implemented by subclass' }
sub remove { croak 'Method "remove" not implemented by subclass' }
sub start { croak 'Method "start" not implemented by subclass' }
sub stop { croak 'Method "stop" not implemented by subclass' }
sub timer { croak 'Method "timer" not implemented by subclass' }
sub watch { croak 'Method "watch" not implemented by subclass' }

sub next_tick { shift->timer(0 => @_) and return undef }

sub one_tick { croak 'Method "one_tick" not implemented by subclass' }
sub recurring { croak 'Method "recurring" not implemented by subclass' }
sub remove { croak 'Method "remove" not implemented by subclass' }
sub start { croak 'Method "start" not implemented by subclass' }
sub stop { croak 'Method "stop" not implemented by subclass' }
sub timer { croak 'Method "timer" not implemented by subclass' }
sub watch { croak 'Method "watch" not implemented by subclass' }

1;

Expand Down Expand Up @@ -134,6 +137,13 @@ tainted sockets.
Check if reactor is running. Meant to be overloaded in a subclass.
=head2 next_tick
my $undef = $reactor->next_tick(sub {...});
Invoke callback as soon as possible, but not before returning, always returns
C<undef>.
=head2 one_tick
$reactor->one_tick;
Expand All @@ -153,9 +163,6 @@ the reactor, so you need to be careful. Meant to be overloaded in a subclass.
Create a new recurring timer, invoking the callback repeatedly after a given
amount of time in seconds. Meant to be overloaded in a subclass.
# Invoke as soon as possible
$reactor->recurring(0 => sub { say 'Reactor tick.' });
=head2 remove
my $bool = $reactor->remove($handle);
Expand Down Expand Up @@ -184,9 +191,6 @@ Stop watching for I/O and timer events. Meant to be overloaded in a subclass.
Create a new timer, invoking the callback after a given amount of time in
seconds. Meant to be overloaded in a subclass.
# Invoke as soon as possible
$reactor->timer(0 => sub { say 'Next tick.' });
=head2 watch
$reactor = $reactor->watch($handle, $readable, $writable);
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojolicious/Guides/Cookbook.pod
Expand Up @@ -61,11 +61,11 @@ C<1>).

Your application is preloaded in the manager process during startup, to run
code whenever a new worker process has been forked you can use
L<Mojo::IOLoop/"timer">.
L<Mojo::IOLoop/"next_tick">.

use Mojolicious::Lite;

Mojo::IOLoop->timer(0 => sub {
Mojo::IOLoop->next_tick(sub {
app->log->info("Worker $$ star...ALL GLORY TO THE HYPNOTOAD!");
});

Expand Down
38 changes: 19 additions & 19 deletions t/mojo/delay.t
Expand Up @@ -14,7 +14,7 @@ my $delay = Mojo::IOLoop::Delay->new;
my @results;
for my $i (1, 1) {
my $end = $delay->begin;
Mojo::IOLoop->timer(0 => sub { push @results, $i; $end->() });
Mojo::IOLoop->next_tick(sub { push @results, $i; $end->() });
}
my $end = $delay->begin;
my $end2 = $delay->begin;
Expand All @@ -40,7 +40,7 @@ my $result;
$delay->on(finish => sub { shift; $result = [@_] });
for my $i (1, 2) {
my $end = $delay->begin(0);
Mojo::IOLoop->timer(0 => sub { $end->($i) });
Mojo::IOLoop->next_tick(sub { $end->($i) });
}
is_deeply [$delay->wait], [1, 2], 'right return values';
is_deeply $result, [1, 2], 'right results';
Expand All @@ -49,7 +49,7 @@ is_deeply $result, [1, 2], 'right results';
$delay = Mojo::IOLoop::Delay->new;
for my $i (1, 2) {
my $end = $delay->begin(0);
Mojo::IOLoop->timer(0 => sub { $end->($i) });
Mojo::IOLoop->next_tick(sub { $end->($i) });
}
is scalar $delay->wait, 1, 'right return value';

Expand All @@ -63,12 +63,12 @@ $delay->steps(
my $delay = shift;
my $end = $delay->begin;
$delay->begin->(3, 2, 1);
Mojo::IOLoop->timer(0 => sub { $end->(1, 2, 3) });
Mojo::IOLoop->next_tick(sub { $end->(1, 2, 3) });
},
sub {
my ($delay, @numbers) = @_;
my $end = $delay->begin;
Mojo::IOLoop->timer(0 => sub { $end->(undef, @numbers, 4) });
Mojo::IOLoop->next_tick(sub { $end->(undef, @numbers, 4) });
},
sub {
my ($delay, @numbers) = @_;
Expand All @@ -93,7 +93,7 @@ is $result, 'success', 'right result';
$delay = Mojo::IOLoop::Delay->new;
$delay->on(finish => sub { $finished++ });
$delay->steps(
sub { Mojo::IOLoop->timer(0 => shift->begin) },
sub { Mojo::IOLoop->next_tick(shift->begin) },
sub {
$result = 'fail';
shift->pass;
Expand Down Expand Up @@ -130,12 +130,12 @@ $delay->steps(
sub {
my $delay = shift;
my $end = $delay->begin;
Mojo::IOLoop->timer(0 => sub { $end->(1, 2, 3) });
Mojo::IOLoop->next_tick(sub { $end->(1, 2, 3) });
},
sub {
my ($delay, @numbers) = @_;
my $end = $delay->begin;
Mojo::IOLoop->timer(0 => sub { $end->(undef, @numbers, 4) });
Mojo::IOLoop->next_tick(sub { $end->(undef, @numbers, 4) });
}
);
is_deeply [$delay->wait], [2, 3, 4], 'right return values';
Expand All @@ -148,10 +148,10 @@ $delay = Mojo::IOLoop->delay(
my $first = shift;
$first->on(finish => sub { $finished++ });
my $second = Mojo::IOLoop->delay($first->begin);
Mojo::IOLoop->timer(0 => $second->begin);
Mojo::IOLoop->timer(0 => $first->begin);
Mojo::IOLoop->next_tick($second->begin);
Mojo::IOLoop->next_tick($first->begin);
my $end = $second->begin(0);
Mojo::IOLoop->timer(0 => sub { $end->(1, 2, 3) });
Mojo::IOLoop->next_tick(sub { $end->(1, 2, 3) });
},
sub {
my ($first, @numbers) = @_;
Expand All @@ -178,14 +178,14 @@ is_deeply $result, [1, 2, 3, 2, 3, 2, 1, 4, 5, 6, 23], 'right results';
my $double = sub {
my ($delay, $num) = @_;
my $end = $delay->begin(0);
Mojo::IOLoop->timer(0 => sub { $end->($num * 2) });
Mojo::IOLoop->next_tick(sub { $end->($num * 2) });
};
$result = undef;
$delay = Mojo::IOLoop::Delay->new->data(num => 9)->steps(
sub {
my $delay = shift;
my $end = $delay->begin(0);
Mojo::IOLoop->timer(0 => sub { $end->($delay->data('num')) });
Mojo::IOLoop->next_tick(sub { $end->($delay->data('num')) });
unshift @{$delay->remaining}, $double;
},
sub {
Expand Down Expand Up @@ -216,7 +216,7 @@ ok !$result, 'no result';
$delay = Mojo::IOLoop::Delay->new;
$delay->on(error => sub { $failed = pop });
$delay->on(finish => sub { $finished++ });
$delay->steps(sub { Mojo::IOLoop->timer(0 => shift->begin) },
$delay->steps(sub { Mojo::IOLoop->next_tick(shift->begin) },
sub { die 'Last step!' });
is scalar $delay->wait, undef, 'no return value';
like $failed, qr/^Last step!/, 'right error';
Expand All @@ -228,7 +228,7 @@ $delay = Mojo::IOLoop::Delay->new;
$delay->on(error => sub { $failed = pop });
$delay->on(finish => sub { $finished++ });
$delay->steps(
sub { Mojo::IOLoop->timer(0 => shift->begin) },
sub { Mojo::IOLoop->next_tick(shift->begin) },
sub { die 'Second step!' },
sub { $result = 'failed' }
);
Expand All @@ -243,10 +243,10 @@ $delay = Mojo::IOLoop::Delay->new;
$delay->on(error => sub { $failed = pop });
$delay->on(finish => sub { $finished++ });
$delay->steps(
sub { Mojo::IOLoop->timer(0 => shift->begin) },
sub { Mojo::IOLoop->next_tick(shift->begin) },
sub {
Mojo::IOLoop->timer(0 => sub { Mojo::IOLoop->stop });
Mojo::IOLoop->timer(0 => shift->begin);
Mojo::IOLoop->next_tick(sub { Mojo::IOLoop->stop });
Mojo::IOLoop->next_tick(shift->begin);
die 'Second step!';
},
sub { $result = 'failed' }
Expand All @@ -260,7 +260,7 @@ ok !$result, 'no result';
Mojo::IOLoop->singleton->reactor->unsubscribe('error');
$delay = Mojo::IOLoop::Delay->new;
ok !$delay->has_subscribers('error'), 'no subscribers';
$delay->steps(sub { Mojo::IOLoop->timer(0 => shift->begin) },
$delay->steps(sub { Mojo::IOLoop->next_tick(shift->begin) },
sub { die 'Oops!' });
eval { $delay->wait };
like $@, qr/Oops!/, 'right error';
Expand Down
4 changes: 2 additions & 2 deletions t/mojo/ioloop.t
Expand Up @@ -28,8 +28,8 @@ is ref $loop->reactor, 'MyReactor', 'right class';

# Double start
my $err;
Mojo::IOLoop->timer(
0 => sub {
Mojo::IOLoop->next_tick(
sub {
eval { Mojo::IOLoop->start };
$err = $@;
Mojo::IOLoop->stop;
Expand Down
4 changes: 2 additions & 2 deletions t/mojo/reactor_ev.t
Expand Up @@ -23,7 +23,7 @@ is ref $reactor, 'Mojo::Reactor::EV', 'right object';

# Make sure it stops automatically when not watching for events
my $triggered;
Mojo::IOLoop->timer(0.25 => sub { $triggered++ });
Mojo::IOLoop->next_tick(sub { $triggered++ });
Mojo::IOLoop->start;
ok $triggered, 'reactor waited for one event';
my $time = time;
Expand Down Expand Up @@ -135,7 +135,7 @@ ok !$timer, 'timer was not triggered';
ok $recurring, 'recurring was triggered again';
$reactor->remove($id);
($readable, $writable, $timer, $recurring) = ();
$reactor->timer(0.025 => sub { shift->stop });
$reactor->next_tick(sub { shift->stop });
$reactor->start;
ok $readable, 'handle is readable again';
ok $writable, 'handle is writable again';
Expand Down
4 changes: 2 additions & 2 deletions t/mojo/reactor_poll.t
Expand Up @@ -21,7 +21,7 @@ is ref $reactor, 'Mojo::Reactor::Poll', 'right object';

# Make sure it stops automatically when not watching for events
my $triggered;
Mojo::IOLoop->timer(0.25 => sub { $triggered++ });
Mojo::IOLoop->next_tick(sub { $triggered++ });
Mojo::IOLoop->start;
ok $triggered, 'reactor waited for one event';
my $time = time;
Expand Down Expand Up @@ -133,7 +133,7 @@ ok !$timer, 'timer was not triggered';
ok $recurring, 'recurring was triggered again';
$reactor->remove($id);
($readable, $writable, $timer, $recurring) = ();
$reactor->timer(0.025 => sub { shift->stop });
$reactor->next_tick(sub { shift->stop });
$reactor->start;
ok $readable, 'handle is readable again';
ok $writable, 'handle is writable again';
Expand Down
6 changes: 3 additions & 3 deletions t/mojo/user_agent.t
Expand Up @@ -448,12 +448,12 @@ is_deeply \@kept_alive, [undef, 1, 1], 'connections kept alive';
$ua->get(
'/' => sub {
push @kept_alive, pop->kept_alive;
Mojo::IOLoop->timer(
0 => sub {
Mojo::IOLoop->next_tick(
sub {
$ua->get(
'/' => sub {
push @kept_alive, pop->kept_alive;
Mojo::IOLoop->timer(0 => sub { Mojo::IOLoop->stop });
Mojo::IOLoop->next_tick(sub { Mojo::IOLoop->stop });
}
);
}
Expand Down
2 changes: 1 addition & 1 deletion t/mojolicious/external/myapp2.pl
Expand Up @@ -15,7 +15,7 @@
# Delay dispatching
hook around_dispatch => sub {
my ($next, $c) = @_;
Mojo::IOLoop->timer(0 => sub { $next->() });
Mojo::IOLoop->next_tick(sub { $next->() });
};

get '/' => sub {
Expand Down
4 changes: 2 additions & 2 deletions t/mojolicious/group_lite_app.t
Expand Up @@ -27,8 +27,8 @@ under('/missing' => sub {1})->route->to('does_not_exist#not_at_all');
under '/suspended' => sub {
my $self = shift;

Mojo::IOLoop->timer(
0 => sub {
Mojo::IOLoop->next_tick(
sub {
return $self->render(text => 'stopped!') unless $self->param('ok');
$self->stash(suspended => 'suspended!');
$self->continue;
Expand Down
4 changes: 2 additions & 2 deletions t/mojolicious/lib/MojoliciousTest/Foo.pm
Expand Up @@ -65,8 +65,8 @@ sub suspended {
my $self = shift;

$self->res->headers->append('X-Suspended' => $self->match->current);
Mojo::IOLoop->timer(
0 => sub {
Mojo::IOLoop->next_tick(
sub {
$self->res->headers->append('X-Suspended' => $self->match->current);
$self->continue;
}
Expand Down

0 comments on commit 245b93c

Please sign in to comment.