Search code examples
angularionic-frameworkfirebase-realtime-databaserxjsangularfire

Timeout observable subscription without value


I'm subscribing to an observable returning values from Firebase. If something is off with the connection I want the subscription to time out. What is the correct way of doing this? I tried the following but this is timing out 20 seconds after I received the last value:

let chatSubscription = this.getChats().timeoutWith(20000, Observable.throw(new Error('timeout'))).subscribe(chats => { ... });

//edit: getChats()

getChats() {
        return Observable.create(observer => {
            let chatList = this.db.list('/users/' + this.auth.user.uid + '/chats').timeoutWith(20000, Observable.throw(new Error('timeout'))).subscribe(chats => {
                observer.next(chats);
            });  
            //keep track of this subscription
            this.openSubscriptions.push(chatList);  
        });
    }

Solution

  • You can use race to listen to whichever observable first produces something:

    const chats = this.db.list('/users/' + this.auth.user.uid + '/chats');
    const timeout = Observable.throw(new Error("timed out")).delay(20000);
    const chatWithTimeout = Observable.race(chats, timeout);
    chatWithTimeout.subscribe(msg => ..., err => ...);
    

    Also, your usage of Observable.create seems a bit unorthodox. I'd suggest taking the above code and just using it as your getChats:

    getChats() {
        const chats = this.db.list('/users/' + this.auth.user.uid + '/chats');
        const timeout = Observable.throw(new Error("timed out")) .delay(20000);
        const chatWithTimeout = Observable.race(chats, timeout);
        return chatWithTimeout;
    }
    
    // usage
    const subscription = foo.getChats().subscribe(...);
    

    With this version there's no need for you to keep a list of open subscriptions. Let the observer keep track of this subscription themselves.