Catalyst event loops only reaching a single client at a time

210 Views Asked by At

I'm working on a Catalyst/psgi application that would make great use of asychronous streaming, however beyond a simple timer (like here: http://www.catalystframework.org/calendar/2013/13), I'm a little stumped on how to implement more "global" events.

By global events, I mean things like:

  1. a periodic timer that is the same for all clients
  2. the visit to a given page by a single client (but updates all clients)
  3. a file stat watcher that will update all clients when a file changes.

Correct me if I'm wrong, but to me these all seem very different from the example linked above, which will give each client a different counter. I would like to have events that happen "across the board."

An example of what I've tried (using #2 from my list above):

has 'write_fh' => ( is => 'rw', predicate => 'has_write_fh' );

sub events : Path('/stream') Args(0) {
    my ( $self, $c ) = @_;
    $c->res->body("");
    $c->res->content_type('text/event-stream');

    $self->write_fh( $c->res->write_fh() );
}

sub trigger : Path('/trigger') : Args(0) {
    my ( $self, $c ) = @_;

    $self->write_fh->write( *the event string* );
}

When I run this, it actually gets further than I would expect - the event does get triggered, but unreliably. With two browsers open, sometimes the event is sent to one, and sometimes to the other.

Now, I think I understand why this would never work - the client who hits /trigger, has no knowledge of all the other clients who are watching /stream, and so the write_fh I'm trying to use is not useful.

But if each client's request is in its own contained bubble, how am I to access their stream from some other request?

Or am I completely on the wrong track...?

1

There are 1 best solutions below

0
On

Your problem with write_fh is that this event is singlecast - once it was received by anyone, it won't be received anymore. so one of the connections catch it, and the other simply don't.

you need to broadcast your events. Take a look at AnyEvent::IRC to see how it can be done.

(note that it was written for an old version of AnyEvent, but it should still work)