jhthorsen / mojo-redis

Non-blocking Redis driver using Mojo::IOLoop
https://metacpan.org/pod/Mojo::Redis
14 stars 11 forks source link

How to use blpop_p within a Mojolicious::Lite app? #57

Closed jezwhite closed 4 years ago

jezwhite commented 4 years ago

Hi,

I am probably using this module wrong:)

I have an existing script working using Mojo::Redis, Mojo::IOLoop and Mojo::UserAgent. The logic is driven by sitting on a queue via blpop_p (with a zero timeout) and it seems to work well.

I am now trying to get something similar working inside a Mojolicious::Lite app but I can't seem to get it working. For some reason promise->wait doesn't seem to actually wait? CPU goes high, with logging messages going to the console.

I am assuming this isn't a bug, but me doing something wrong?

Regards,

#!/usr/bin/env perl
use warnings;
use strict;

use Mojolicious::Lite -signatures;
use Mojo::Redis;
use Mojo::IOLoop;
my $RedisURL = 'xxx:6379';

my $mR = Mojo::Redis->new('redis://'.$RedisURL);
my $r = $mR->db;

sub StartRedisLoop {
  print "StartLoop $r\n";
  while(1) {
    GetEvent();
  }
}

sub GetEvent {
  my $promise =  $r->blpop_p('queue',0);
  $promise->then( sub {
    my ($data,$queue) =@_;
    print "got data: $data\n";
  });
  $promise->catch( sub {
    my $ans = shift;
    print "Catch Error: $ans\n";
  });  
  print "pre wait\n";
  $promise->wait();
  print "post wait\n";
}

websocket '/socket' => sub ($c) {
  $c->inactivity_timeout(0); #no timeout...
  $c->on(message => sub ($c, $msg) { print "$msg\n" });
};

my $app = app->start;
#Start the redis loop in 5 seconds...
Mojo::IOLoop->timer(5 => sub ($loop) { StartRedisLoop()});
return $app;
jhthorsen commented 4 years ago

Your problem is in StartRedisLoop() where you have an infinite while(1) loop. It won't really wait() on the promise, since the IOLoop is already running. See https://docs.mojolicious.org/Mojo/Promise#wait

Start "ioloop" and stop it again once the promise has been fulfilled or rejected, does nothing when "ioloop" is already running.

This will work though:

sub StartRedisLoop {
  print "StartLoop $r\n";
  GetEvent().then(StartRedisLoop);
}

sub GetEvent {
  return $r->blpop_p('queue',0)->then( sub {
    my ($data,$queue) =@_;
    print "got data: $data\n";
  })->catch( sub {
    my $ans = shift;
    print "Catch Error: $ans\n";
  });
}

I think these kinds of questions are better to be asked in #mojo on irc.freenode.net. You will probably get your problem solved faster as well.