voryx/angular-wamp

Re-subscribing after reconnect

Closed this issue · 6 comments

Sorry for the issue spam (:

The issue I'm trying to resolve is how to keep a subscription that is persistent across reconnects. Normally, when coding to AutobahnJS, you establish all the subscriptions in the connection.onopen callback.

However, this doesn't work here. If I call $wamp.subscribe, I will have the subscription be made for me as soon as the connection opens via your callback queue, but nothing will happen on reconnect. As such, I'm ending up doing something like this:

        WsBindValue.prototype.init = function () {
            this.subscribe();

            $rootScope.$on(
                '$wamp.open',
                WsBindValue.prototype.subscribe.bind(this)
            );
        };

        WsBindValue.prototype.subscribe = function () {
            $wamp.subscribe(
                this.topic,
                WsBindValue.prototype.onUpdate.bind(this)
            ).then(
                WsBindValue.prototype.onSubscribed.bind(this),
                this.reject
            );
        };

It's a little bit verbose and not very DRY.

One way this could be addressed would be with an alternate subscribePersistent method that takes an additional argument for a callback that lets me attach promises to each subscription attempt, e.g.

$wamp.subscribePersistent(
    topic, handler, options,
    function (subscriptionPromise) {
        subscriptionPromise.then(...);
    }
);

This can then attempt to resubscribe each time we hit $wamp.open. It would take a bit more work to get unsubscribing to work properly.

@taion Don't worry about opening multiple issues. Open issues mean that people are using this project, which is exactly what it's here for.

I'm wondering if there is a need to conditionally persist the subscriptions. A simpler solution might be to keep track of all subscriptions and unsubscriptions, in the order that they're called, and then when it reconnects, reprocess them.

I'll work on this and let you know when I have something.

Here's my use case, and why I think it's useful to persist subscriptions per se, and why I'd need something like the above:

I want to build something that works a little bit like Firebase or Meteor, but have it be backed by a PostgreSQL instance that I host. Specifically, I want to be able to "subscribe" to a table, and have a bunch of stuff in the background keep around a local data structure that mirrors that table.

I'm implementing this by subscribing to a topic for the updates to the table, then invoking a "get snapshot" procedure via RPC that lets me get a snapshot of the part of the table that I'm interested in.

For this to work properly, I need to be able to re-request that snapshot every time I re-make the subscription, to make sure I didn't miss any updates to this table while my subscription was down. This is why I'm proposing that 4th argument that takes a callback that is given the promise for the subscription every time the subscription is made.

@taion I just committed an update to subscriptions. You can now do something like:

        var reconnectCallback = function (subscription) {
            //Called each time the client connects including the first time 
        };

        $wamp.subscribe("com.example.oncounter", function (args) {
            console.log(args);
        }, [], reconnectCallback)
            .then(function (subscription) {
                //Called only the first time you subscribe
            }
        );

Let me know if that works for you.

In this context, how can I be notified if e.g. the resubscribe on reconnect fails?

How about something like this instead?

var reconnectCallback = function (promise) {
    //Called each time the client connects including the first time 
    promise.then(
        function (subscription) {
        },
        function (error) {

        }
    );
};

$wamp.subscribe("com.example.oncounter", function (args) {
    console.log(args);
}, [], reconnectCallback)
    .then(function (subscription) {
        //Called only the first time you subscribe
    }
);

That's exactly what I'm looking for/was thinking about, thanks.