0
votes

I'm using RXJS websocket for my application. After logging in data is send from my server to the client and the data is stored in an observable using shareReplay to keep the data when navigating the application.

if(!this.data$ || this.data$Completed) {
    this.data$ = this.dataService.get(this.CTRL, 'list').pipe(
        finalize(() => {
            console.log('finalizing data list');
            this.data$Completed = true;
        }),
        map(data => [....]), // irrelevant
        tap((d) => console.log('data: ', d)),
        shareReplay(1),
        tap((d) => console.log('data 2: ', d)),
    );
}

Console output is as intended

// first subscribe
data:  [{…}]
data 2:  [{…}]
// every other subscribe when resubscribing after navigation / different components
data 2:  [{…}]
data 2:  [{…}]
data 2:  [{…}]
...

When logging off the connection is terminated and the finalize method is triggered. When loggin back in the data is send again, but the shareReplay does not work anymore. I get data only on the first subscribe, but not after navigating and resubscribing.

// logout
finalizing data list

// logging in again
data:  [{…}]
data 2:  [{…}]

I also noticed that the rxjs websocket multiplex in that case sends subscribe commands to the server, so obvisously I subscribe to the websocket subject and not the ReplaySubject.

2
How do you subscribe (or |async) to your rs ? It's not in the code, and remember that a pipe won't do anything by itself, it's the subscribe that "activate" the whole thing. - Jean-Xavier Raynaud
I subscribe to the observable using async in my html, but I also tried it with a subscribe call in a component, the result is the same. - Fussel

2 Answers

0
votes

When finalize is called, this means that the source Observable has completed. You cannot restart a completed Observable. The data$ still emits on subscribe, because that's the idea of shareReplay, it just gives you the last emitted value on subscribe, regardless if the source is completed. It will however never get new data.

You will have to recreate your data$ observable when you login again, to get a new and fresh observable.

-2
votes

I'm kind of rusty with rs and subject in general because I use ngrx for storing data in every app I worked on recently, but the with websockets the logic is a bit different than we classical api, because the websocket itself is a Subject and will recreate itself every time it reconnects. When that happens all the underlying subscription dies. Sadly it means that we cannot use the logic of API calls where a component subscribe to a first observable and a chain of pipes "fires" the api service.

Instead, what we did was to use a subscription directly in the data service that has the ws subject. That's safe because every time the websocket is disconnected, it emits a completed event and thus the subscription dies. This subscription is in charge of pushing the data into the ngrx store by triggering actions, which is basically a call to next.

The service is designed using websocket config option to reconnect every time it loses the connection, and on login. On reco it recreates both a websocket subject and the underlying subscription that push data into ngrx.