question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How best to release elements in a ReplaySubject?

See original GitHub issue

Hi,

We’re using ReplaySubject to keep a streamed response from a server into a buffer, in order to be able to pass the whole (finite) sequence to observables that subscribe to the subject.

The whole sequence may take a bit of time to complete, but we want to pass the Observable right away to client code.Furthermore, client code may not immediately subscribe to the flow, or it could subscribe several time to do multiple processing of the sequence.

Thus the use of ReplaySubject to avoid replaying the original request each time, and to avoid blocking for the server to respond with the whole sequence.

However, said elements are resources that are reference counted and should be manually freed before being garbage collected. What do you think is the best approach to cope with that?

Maybe what we need is to add semantics on the ReplaySubject to do cleanup and clear the buffer (like a dispose() or release() method)? This would probably also be needed in the bounded ReplaySubject to plug in cleanup behavior at eviction time…

Maybe there is a better alternative to ReplaySubject? Or a simple solution like foreaching on the items and cleaning them up this way?

I hope someone will be able to make a suggestion, and I’d be delighted to contribute if it makes sense 😉 Thanks!

Issue Analytics

  • State:closed
  • Created 9 years ago
  • Comments:17 (17 by maintainers)

github_iconTop GitHub Comments

3reactions
benjchristensencommented, Oct 25, 2014

Using Subjects directly are almost never the desired solution as they don’t compose with backpressure or resource cleanup (unsubscription). Subjects are very imperative in use and “hot” in how data flows through them.

For example, using cache() internally uses ReplaySubject but it will be garbage collected once references to the Observables are released. Or replay().refCount() is even better, as once all Subscribers are done it will unsubscribe up the chain and dispose of the underlying ReplaySubject.

Your use case however sounds like you should use Observable.create to represent your data source since then you can manage the cleanup as you need to (since you need to manage the reference counting).

Thus, I suggest something like the following:

import java.util.Arrays;
import java.util.Collection;

import rx.Observable;
import rx.schedulers.Schedulers;
import rx.subscriptions.Subscriptions;

public class ObservableCreateWithCleanup {

    public static void main(String[] args) {
        System.out.println("fetch slow data...");
        getData().toBlocking().forEach(System.out::println);
        // sleep so the JVM doesn't shut down before we see cleanup
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
        }
    }

    public static Observable<Data> getData() {
        return Observable.<Data> create(subscriber -> {
            try {
                Collection<Data> data = slowSynchronousCall();
                // completely ignoring backpressure and not using setProducer for simplicity here
                for(Data d : data) {
                    subscriber.onNext(d);
                }
                subscriber.onCompleted();
                // register subscription
                subscriber.add(Subscriptions.create(() -> {
                    try {
                        // do the manual refcount release
                        for(Data d : data) {
                            d.release();
                        }
                    }catch(Throwable e) {
                        // never throw while unsubscribing
                        e.printStackTrace();
                    }
                }));
            }catch(Throwable e) {
                subscriber.onError(e);
            }
        }).subscribeOn(Schedulers.io());
    }

    /**
     * Assuming the slow call is synchronous. And I'm making this be a single collection rather than a stream to the Observable.
     * 
     * @param id
     * @return
     */
    public static Collection<Data> slowSynchronousCall() {
        try {
            // simulate slow
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
        return Arrays.asList(new Data(1), new Data(2), new Data(3));
    }

    public static class Data {
        private final int id;

        public Data(int id) {
            this.id = id;
        }

        public void release() {
            System.out.println("Releasing " + toString());
        }

        @Override
        public String toString() {
            return "Data => " + id;
        }
    }
}

This outputs:

fetch slow data...
Data => 1
Data => 2
Data => 3
Releasing Data => 1
Releasing Data => 2
Releasing Data => 3
2reactions
simonbaslecommented, Feb 5, 2015

getValues() right? awesome 😍

Read more comments on GitHub >

github_iconTop Results From Across the Web

How Can I remove some element in a ReplaySubject in Rxjs?
I am trying to write a message service with Rxjs and angular 6. I use a ReplaySubject to keep the sent messages, then...
Read more >
Understanding rxjs BehaviorSubject, ReplaySubject and ...
There are two ways to get this last emited value. You can either get the value by accessing the .value property on the...
Read more >
ReplaySubject - RxJS Reference - InDepth.Dev
When an observer subscribes to a ReplaySubject, the subject begins by first emitting all values from the cache and then continues to emit...
Read more >
When Use RxJS Subject, BehaviourSubject, ReplaySubject ...
It sounds logical to use a Subject over an Observable. But I don't know what to effects are on performance in the browser....
Read more >
ReplaySubject - RxJS
bufferSize - This will determine how many items are stored in the buffer, defaults to infinite. windowTime - The amount of time to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found