Make RxJavaPlugins.reset() public #2297

Closed
TomRK1089 opened this Issue Dec 30, 2014 · 18 comments

Comments

Projects
None yet
@TomRK1089

Let me preface this by saying the RxJava library has made my life easier in just the short time I've been using it. However, there's one jagged edge that bit me today.

I'm attempting to use the RxJavaPlugins class to override the default schedulers via registerSchedulersHook. However, I want to only override the defaults for a single JUnit test. Ideally, I would call RxJavaPlugins.getInstance().reset() in my @After method...but I can't, because it is package private.

I could get at it via reflection, but it'd be easier if it was public -- unless there is a) a very good reason it is not or b) there is an obvious alternative I am missing (always a possibility!)

@benjchristensen

This comment has been minimized.

Show comment
Hide comment
@benjchristensen

benjchristensen Dec 30, 2014

Member

I'm open to making it public. Do you want to submit the PR to make the change?

There are 2 reasons it is not public:

  1. I avoid making things public until they need to be as once public it must be supported for a very long time.
  2. The drawback ... resetting the plugins is not safe during application runtime and also bad code could invoke it in the middle of an application life-cycle and really break things. For example, a 3rd party transitive library that abusively calls reset() in order to always register its plugin automatically in place of anything else already registered.

Of course, if someone wants to do that bad thing we can't prevent it anyways, since all someone has to do is put a class inside the same package and invoke reset from there. So the "security drawback" isn't a strong enough reason to avoid it. And the non-safe issue is one developers will just have to understand and use it wisely. In other words, reset should never be called during normal application operation.

/cc @akarnokd @mattrjacobs @abersnaze for your thoughts on this

Member

benjchristensen commented Dec 30, 2014

I'm open to making it public. Do you want to submit the PR to make the change?

There are 2 reasons it is not public:

  1. I avoid making things public until they need to be as once public it must be supported for a very long time.
  2. The drawback ... resetting the plugins is not safe during application runtime and also bad code could invoke it in the middle of an application life-cycle and really break things. For example, a 3rd party transitive library that abusively calls reset() in order to always register its plugin automatically in place of anything else already registered.

Of course, if someone wants to do that bad thing we can't prevent it anyways, since all someone has to do is put a class inside the same package and invoke reset from there. So the "security drawback" isn't a strong enough reason to avoid it. And the non-safe issue is one developers will just have to understand and use it wisely. In other words, reset should never be called during normal application operation.

/cc @akarnokd @mattrjacobs @abersnaze for your thoughts on this

@TomRK1089

This comment has been minimized.

Show comment
Hide comment
@TomRK1089

TomRK1089 Dec 30, 2014

Some good points. I definitely agree with "as private as possible" by default.

After looking into it some more, I see that my use case would not precisely be served by this -- even if I could re-register a different hook, the Scheduler class will have already assigned its instance fields for io, computation, etc.

For now I am solving my testing issue by injecting a Scheduler with Guice which is annotated with @Named("io"), and in the test substituting Schedulers.test() for that scheduler. I'm not sure I love that approach as the scheduler doesn't feel like a "real" dependency, and it's another thing which must be configured in the DI container... Another approach might be to sidestep the public API and swap out schedulers using something like PowerMock.

So, rambling aside -- making reset() public still would not let me tweak the default schedulers on a per-test basis. If I think of an alternative approach which doesn't seem to compromise the safety of the rest of the API I'll submit a PR.

Some good points. I definitely agree with "as private as possible" by default.

After looking into it some more, I see that my use case would not precisely be served by this -- even if I could re-register a different hook, the Scheduler class will have already assigned its instance fields for io, computation, etc.

For now I am solving my testing issue by injecting a Scheduler with Guice which is annotated with @Named("io"), and in the test substituting Schedulers.test() for that scheduler. I'm not sure I love that approach as the scheduler doesn't feel like a "real" dependency, and it's another thing which must be configured in the DI container... Another approach might be to sidestep the public API and swap out schedulers using something like PowerMock.

So, rambling aside -- making reset() public still would not let me tweak the default schedulers on a per-test basis. If I think of an alternative approach which doesn't seem to compromise the safety of the rest of the API I'll submit a PR.

@akarnokd

This comment has been minimized.

Show comment
Hide comment
@akarnokd

akarnokd Jan 1, 2015

Member

Why don't you use operators which let you parametrize the scheduler and not rely on the defaults?

For the other hooks, you could set up a level of indirection, i.e., you register your own hook which then does allow setting/removing further hooks at will. You can even create it such a way that multiple hooks can work at the same time, but you have to implement a separate Observable-Observer and make careful decisions when these hooks return some value instead of just consuming.

Member

akarnokd commented Jan 1, 2015

Why don't you use operators which let you parametrize the scheduler and not rely on the defaults?

For the other hooks, you could set up a level of indirection, i.e., you register your own hook which then does allow setting/removing further hooks at will. You can even create it such a way that multiple hooks can work at the same time, but you have to implement a separate Observable-Observer and make careful decisions when these hooks return some value instead of just consuming.

@akarnokd akarnokd added the Discussion label Feb 5, 2015

@Axxiss

This comment has been minimized.

Show comment
Hide comment
@Axxiss

Axxiss May 7, 2015

As a work around for this what I have done by now is defining a RxJavaTestPlugins class on src/test/java/rx/plugins

public class RxJavaTestPlugins extends RxJavaPlugins {
    RxJavaTestPlugins() {
        super();
    }

    public static void resetPlugins(){
        getInstance().reset();
    }
}

And then invoke resetPlugins() on the tear down setup of my units test before registerSchedulersHook

If your run it on the tearDown there can be another test that uses RxJava then, hence default hook is already loaded and you can't load your custom hook.

Axxiss commented May 7, 2015

As a work around for this what I have done by now is defining a RxJavaTestPlugins class on src/test/java/rx/plugins

public class RxJavaTestPlugins extends RxJavaPlugins {
    RxJavaTestPlugins() {
        super();
    }

    public static void resetPlugins(){
        getInstance().reset();
    }
}

And then invoke resetPlugins() on the tear down setup of my units test before registerSchedulersHook

If your run it on the tearDown there can be another test that uses RxJava then, hence default hook is already loaded and you can't load your custom hook.

@JakeWharton

This comment has been minimized.

Show comment
Hide comment
@JakeWharton

JakeWharton May 7, 2015

Member

I very much would like something like this, too.

I do something similar to what you have but as a JUnit rule so it can be used as:

@Rule public final RxJavaPluginsResetRule pluginsReset = new RxJavaPluginsResetRule();

and it calls .reset() automatically both before and after each test.

Member

JakeWharton commented May 7, 2015

I very much would like something like this, too.

I do something similar to what you have but as a JUnit rule so it can be used as:

@Rule public final RxJavaPluginsResetRule pluginsReset = new RxJavaPluginsResetRule();

and it calls .reset() automatically both before and after each test.

@JakeWharton

This comment has been minimized.

Show comment
Hide comment
@JakeWharton

JakeWharton Aug 5, 2015

Member

FYI RxAndroid shipped with a @Beta reset() method public on its RxAndroidPlugins class.

Member

JakeWharton commented Aug 5, 2015

FYI RxAndroid shipped with a @Beta reset() method public on its RxAndroidPlugins class.

@benjchristensen benjchristensen added this to the 1.0.x milestone Aug 28, 2015

@pakerfeldt

This comment has been minimized.

Show comment
Hide comment
@pakerfeldt

pakerfeldt Sep 18, 2015

@JakeWharton Is there really a point of doing .reset() in your Rule? To me it doesn't seem to have the expected effect. Any subsequent call to Schedulers.* will still return the same original Scheduler even after calling .reset(). Since the hooks are only called once when the Schedulers instance is created.

I can't seem to find a valid use case for using RxJavaPlugins to register test schedulers in unit tests really. Maybe it was never intended for that anyway.

@JakeWharton Is there really a point of doing .reset() in your Rule? To me it doesn't seem to have the expected effect. Any subsequent call to Schedulers.* will still return the same original Scheduler even after calling .reset(). Since the hooks are only called once when the Schedulers instance is created.

I can't seem to find a valid use case for using RxJavaPlugins to register test schedulers in unit tests really. Maybe it was never intended for that anyway.

@pakerfeldt

This comment has been minimized.

Show comment
Hide comment
@pakerfeldt

pakerfeldt Sep 18, 2015

Here's an example of how you can accidently misuse TestScheduler to break unrelated tests.
https://github.com/pakerfeldt/rxjava-the-schedulers-pitfall

Here's an example of how you can accidently misuse TestScheduler to break unrelated tests.
https://github.com/pakerfeldt/rxjava-the-schedulers-pitfall

@pakerfeldt

This comment has been minimized.

Show comment
Hide comment
@pakerfeldt

pakerfeldt Sep 18, 2015

Actually, using a singleton TestScheduler wrapper we can more easily identify when we accidently initialize Schedulers before our hook is called (instead of just getting weird behavior in the test):
https://gist.github.com/pakerfeldt/db297764918e7d464884#file-testschedulerproxy-java

However, that would require all unit tests that happen to execute any code that would initialize Schedulers to first initialize our TestSchedulerProxy (which registers the hook). And possibly also advance / trigger the test scheduler I guess.

Actually, using a singleton TestScheduler wrapper we can more easily identify when we accidently initialize Schedulers before our hook is called (instead of just getting weird behavior in the test):
https://gist.github.com/pakerfeldt/db297764918e7d464884#file-testschedulerproxy-java

However, that would require all unit tests that happen to execute any code that would initialize Schedulers to first initialize our TestSchedulerProxy (which registers the hook). And possibly also advance / trigger the test scheduler I guess.

@mikebaum

This comment has been minimized.

Show comment
Hide comment
@mikebaum

mikebaum Sep 27, 2015

I ran into this exact problem and it was frustrating. I ended up creating the following TestWatcher, which is specific to verifying that there are no leaking subscriptions, but I suppose could be used more generally.

/**
 * This Verifier will assert that any subscriptions created during a test are unsubscribed after the
 * test has finished.<br>
 * 
 * NOTE: It is very important that the call {@link #initialize()} is done before any
 * {@link Observable} is created. Failing to do so, means that the {@link SusbcriptionCollector}
 * would fail to collect any subscriptions.
 */
public class RxTestCaseSubscriptionsVerifier extends TestWatcher
{
    @Override
    protected void starting( Description description )
    {
        SusbcriptionCollector subSusbcriptionCollector = SusbcriptionCollector.getInstance();

        checkState( ! subSusbcriptionCollector.isCollecting(),
                    "Cannot start collecting subscriptions while another SusbcriptionCollector is " +
                    "already collecting." );

        subSusbcriptionCollector.startCollecting();
    }

    @Override
    protected void succeeded( Description description )
    {
        SusbcriptionCollector subSusbcriptionCollector = SusbcriptionCollector.getInstance();

        checkState( subSusbcriptionCollector.isCollecting(), 
                    "Cannot assert all subscriptions are unsubscribed if the SusbcriptionCollector " +
                    "was not collecting subscriptions" );

        subSusbcriptionCollector.assertAllSubscriptionsAreUnsubscribed();
    }

    @Override
    protected void finished( Description description )
    {
        SusbcriptionCollector subSusbcriptionCollector = SusbcriptionCollector.getInstance();

        subSusbcriptionCollector.reset();

        checkState( ! subSusbcriptionCollector.isCollecting(), 
                    "The SusbcriptionCollector should not be collecting once reset" );
    }

    /**
     * See NOTE in the class documentation.
     */
    public static void initialize()
    {
        SusbcriptionCollector.getInstance();
    }

    private static class SusbcriptionCollector
    {
        private static SusbcriptionCollector INSTANCE = null;

        private final Map<Subscription, String> mSubscriptions =  Collections.synchronizedMap( Maps.newHashMap() );
        private volatile boolean mShouldCollect = false;

        private SusbcriptionCollector()
        {
            RxJavaPlugins.getInstance().registerObservableExecutionHook( createSubscriptionCollector() );
        }

        static synchronized SusbcriptionCollector getInstance()
        {
            if ( INSTANCE == null )
                INSTANCE = new SusbcriptionCollector();

            return INSTANCE;
        }

        void startCollecting()
        {
            mShouldCollect = true;
        }

        public void assertAllSubscriptionsAreUnsubscribed()
        {
            synchronized( mSubscriptions )
            {
                for ( Map.Entry<Subscription, String> entry : mSubscriptions.entrySet() )
                {
                    if ( ! entry.getKey().isUnsubscribed() )
                    {
                        fail( "There was an non-unsubscribed subscription detected " +
                              "which was created at the following place:\n" +
                              "<-------------------- start unsubscribed stack -------------------->\n" + 
                              entry.getValue() +
                              "<--------------------- end unsubscribed stack --------------------->" );
                    }
                }
            }
        }

        private void reset()
        {
            synchronized( mSubscriptions )
            {                
                mSubscriptions.clear();
                mShouldCollect = false;
            }
        }

        private boolean isCollecting()
        {
            return mShouldCollect;
        }

        private RxJavaObservableExecutionHook createSubscriptionCollector()
        {
            return new RxJavaObservableExecutionHook()
            {
                @Override
                public <T extends Object> Subscription onSubscribeReturn( Subscription subscription )
                {
                    if ( ! mShouldCollect )
                        return subscription;

                    String stackTrace = Debug.getStackTrace( new Exception( "Subscription not unsubscribed." ) );
                    mSubscriptions.put( subscription, stackTrace );
                    return subscription;
                };
            };
        }
    }
}

then in the test you need to add the following:

@Rule public final TestRule mSubscriptionsVerifier = new RxTestCaseSubscriptionsVerifier();

or in a Test Suite class you could do this if you want to use the rule on all tests.

    @BeforeClass
    public static void initializeRxVerifier()
    {
        RxTestCaseSubscriptionsVerifier.initialize();
    }

I ran into this exact problem and it was frustrating. I ended up creating the following TestWatcher, which is specific to verifying that there are no leaking subscriptions, but I suppose could be used more generally.

/**
 * This Verifier will assert that any subscriptions created during a test are unsubscribed after the
 * test has finished.<br>
 * 
 * NOTE: It is very important that the call {@link #initialize()} is done before any
 * {@link Observable} is created. Failing to do so, means that the {@link SusbcriptionCollector}
 * would fail to collect any subscriptions.
 */
public class RxTestCaseSubscriptionsVerifier extends TestWatcher
{
    @Override
    protected void starting( Description description )
    {
        SusbcriptionCollector subSusbcriptionCollector = SusbcriptionCollector.getInstance();

        checkState( ! subSusbcriptionCollector.isCollecting(),
                    "Cannot start collecting subscriptions while another SusbcriptionCollector is " +
                    "already collecting." );

        subSusbcriptionCollector.startCollecting();
    }

    @Override
    protected void succeeded( Description description )
    {
        SusbcriptionCollector subSusbcriptionCollector = SusbcriptionCollector.getInstance();

        checkState( subSusbcriptionCollector.isCollecting(), 
                    "Cannot assert all subscriptions are unsubscribed if the SusbcriptionCollector " +
                    "was not collecting subscriptions" );

        subSusbcriptionCollector.assertAllSubscriptionsAreUnsubscribed();
    }

    @Override
    protected void finished( Description description )
    {
        SusbcriptionCollector subSusbcriptionCollector = SusbcriptionCollector.getInstance();

        subSusbcriptionCollector.reset();

        checkState( ! subSusbcriptionCollector.isCollecting(), 
                    "The SusbcriptionCollector should not be collecting once reset" );
    }

    /**
     * See NOTE in the class documentation.
     */
    public static void initialize()
    {
        SusbcriptionCollector.getInstance();
    }

    private static class SusbcriptionCollector
    {
        private static SusbcriptionCollector INSTANCE = null;

        private final Map<Subscription, String> mSubscriptions =  Collections.synchronizedMap( Maps.newHashMap() );
        private volatile boolean mShouldCollect = false;

        private SusbcriptionCollector()
        {
            RxJavaPlugins.getInstance().registerObservableExecutionHook( createSubscriptionCollector() );
        }

        static synchronized SusbcriptionCollector getInstance()
        {
            if ( INSTANCE == null )
                INSTANCE = new SusbcriptionCollector();

            return INSTANCE;
        }

        void startCollecting()
        {
            mShouldCollect = true;
        }

        public void assertAllSubscriptionsAreUnsubscribed()
        {
            synchronized( mSubscriptions )
            {
                for ( Map.Entry<Subscription, String> entry : mSubscriptions.entrySet() )
                {
                    if ( ! entry.getKey().isUnsubscribed() )
                    {
                        fail( "There was an non-unsubscribed subscription detected " +
                              "which was created at the following place:\n" +
                              "<-------------------- start unsubscribed stack -------------------->\n" + 
                              entry.getValue() +
                              "<--------------------- end unsubscribed stack --------------------->" );
                    }
                }
            }
        }

        private void reset()
        {
            synchronized( mSubscriptions )
            {                
                mSubscriptions.clear();
                mShouldCollect = false;
            }
        }

        private boolean isCollecting()
        {
            return mShouldCollect;
        }

        private RxJavaObservableExecutionHook createSubscriptionCollector()
        {
            return new RxJavaObservableExecutionHook()
            {
                @Override
                public <T extends Object> Subscription onSubscribeReturn( Subscription subscription )
                {
                    if ( ! mShouldCollect )
                        return subscription;

                    String stackTrace = Debug.getStackTrace( new Exception( "Subscription not unsubscribed." ) );
                    mSubscriptions.put( subscription, stackTrace );
                    return subscription;
                };
            };
        }
    }
}

then in the test you need to add the following:

@Rule public final TestRule mSubscriptionsVerifier = new RxTestCaseSubscriptionsVerifier();

or in a Test Suite class you could do this if you want to use the rule on all tests.

    @BeforeClass
    public static void initializeRxVerifier()
    {
        RxTestCaseSubscriptionsVerifier.initialize();
    }
@ivacf

This comment has been minimized.

Show comment
Hide comment
@ivacf

ivacf Dec 7, 2015

I also think making reset() public would be very useful for unit testing. At the moment, there isn't a way of calling registerSchedulersHook during local unit tests that doesn't end up throwing java.lang.IllegalStateException: Another strategy was already registered

The closes I got was from the constructor of a custom test Runner but this only works for the first test case, the rest would throw the exception above. So the two option I have is catch the IllegalStateException so once my hook is registered it will live for the rest of the tests or use reflection to call reset. I'm using reflection for now but there should be a better way of achieving this.

ivacf commented Dec 7, 2015

I also think making reset() public would be very useful for unit testing. At the moment, there isn't a way of calling registerSchedulersHook during local unit tests that doesn't end up throwing java.lang.IllegalStateException: Another strategy was already registered

The closes I got was from the constructor of a custom test Runner but this only works for the first test case, the rest would throw the exception above. So the two option I have is catch the IllegalStateException so once my hook is registered it will live for the rest of the tests or use reflection to call reset. I'm using reflection for now but there should be a better way of achieving this.

@mikebaum

This comment has been minimized.

Show comment
Hide comment
@mikebaum

mikebaum Dec 7, 2015

@ivacf Not sure if you are referring to my previous comment, but it's very important that you add:

    @BeforeClass
    public static void initializeRxVerifier()
    {
        RxTestCaseSubscriptionsVerifier.initialize();
    }

to whatever class groups all you're tests. If you don't have a suite that groups tests, then it's possible this might have to be done before each test. Anyway, this was tricky and frustrating for the reasons you already mentioned.

mikebaum commented Dec 7, 2015

@ivacf Not sure if you are referring to my previous comment, but it's very important that you add:

    @BeforeClass
    public static void initializeRxVerifier()
    {
        RxTestCaseSubscriptionsVerifier.initialize();
    }

to whatever class groups all you're tests. If you don't have a suite that groups tests, then it's possible this might have to be done before each test. Anyway, this was tricky and frustrating for the reasons you already mentioned.

@SmartDengg SmartDengg referenced this issue in lzyzsd/Awesome-RxJava Jan 1, 2016

Open

适用场景 #9

@shivangshah

This comment has been minimized.

Show comment
Hide comment
@shivangshah

shivangshah Mar 31, 2016

👍
I was trying to contribute back to spring-cloud-sleuth to have distributed tracing capabilities across RxJava threadpools as well (spring-cloud/spring-cloud-sleuth#235). I am following their current Hystrix implementation strategy : https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/SleuthHystrixConcurrencyStrategy.java#L66
You could reset HystrixPlugins but the same cannot be done right now with RxjavaPlugins. I have to create a wrapper (as mentioned above) in the same rx.plugins folder as a workaround (testing as we speak if it's working or not).
It'd be good to not have to do this workaround.

👍
I was trying to contribute back to spring-cloud-sleuth to have distributed tracing capabilities across RxJava threadpools as well (spring-cloud/spring-cloud-sleuth#235). I am following their current Hystrix implementation strategy : https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/SleuthHystrixConcurrencyStrategy.java#L66
You could reset HystrixPlugins but the same cannot be done right now with RxjavaPlugins. I have to create a wrapper (as mentioned above) in the same rx.plugins folder as a workaround (testing as we speak if it's working or not).
It'd be good to not have to do this workaround.

shivangshah pushed a commit to shivangshah/spring-cloud-sleuth that referenced this issue Mar 31, 2016

Shivang Shah
Adding RxJava Support
1) Because RxJavaPlugins is protected does not expose `reset()`, a wrapper had to be introduced. More details can be found here: ReactiveX/RxJava#2297
2) The implementation (and testing) strategy was followed per HystrixConcurrencyStrategy implementation.
@marcingrzejszczak

This comment has been minimized.

Show comment
Hide comment
@marcingrzejszczak

marcingrzejszczak Apr 1, 2016

Hi! @benjchristensen @akarnokd @mattrjacobs @abersnaze - any news on this? It doesn't seem like a big change and would certainly be helpful in Spring Cloud Sleuth's intergration with RxJava.

Hi! @benjchristensen @akarnokd @mattrjacobs @abersnaze - any news on this? It doesn't seem like a big change and would certainly be helpful in Spring Cloud Sleuth's intergration with RxJava.

shivangshah pushed a commit to shivangshah/spring-cloud-sleuth that referenced this issue Apr 1, 2016

Shivang Shah
Adding RxJava Support
1) Because RxJavaPlugins is protected does not expose `reset()`, a wrapper had to be introduced. More details can be found here: ReactiveX/RxJava#2297
2) The implementation (and testing) strategy was followed per HystrixConcurrencyStrategy implementation.

@akarnokd akarnokd added the PR welcome label Apr 1, 2016

@akarnokd

This comment has been minimized.

Show comment
Hide comment
@akarnokd

akarnokd Apr 1, 2016

Member

I don't use the plugin API so can't tell if its worth it or what consequences it holds. PR welcome.

Member

akarnokd commented Apr 1, 2016

I don't use the plugin API so can't tell if its worth it or what consequences it holds. PR welcome.

shivangshah pushed a commit to shivangshah/spring-cloud-sleuth that referenced this issue Apr 1, 2016

Shivang Shah
Adding RxJava Support
1) Because RxJavaPlugins is protected does not expose `reset()`, a wrapper had to be introduced. More details can be found here: ReactiveX/RxJava#2297
2) The implementation (and testing) strategy was followed per HystrixConcurrencyStrategy implementation.

shivangshah pushed a commit to shivangshah/RxJava that referenced this issue Apr 1, 2016

shivangshah pushed a commit to shivangshah/spring-cloud-sleuth that referenced this issue Apr 1, 2016

Shivang Shah
Adding RxJava Support
1) Because RxJavaPlugins is protected does not expose `reset()`, a wrapper had to be introduced. More details can be found here: ReactiveX/RxJava#2297
2) The implementation (and testing) strategy was followed per HystrixConcurrencyStrategy implementation.
3) Adding integration test cases

@shivangshah shivangshah referenced this issue in spring-cloud/spring-cloud-sleuth Apr 2, 2016

Merged

Support rx java #243

@DavidMGross DavidMGross referenced this issue in ReactiveX/reactivex.github.io Apr 4, 2016

Open

Document RxPlugins.reset(), Schedulers.reset() #225

shivangshah pushed a commit to shivangshah/RxJava that referenced this issue Apr 7, 2016

Shivang Shah
Making RxPlugins reset() public
Discussions found here: ReactiveX#2297
Adding @experimental tag because exposing reset() could be dangerous

shivangshah pushed a commit to shivangshah/RxJava that referenced this issue Apr 22, 2016

Shivang Shah
Making RxPlugins reset() public
Discussions found here: ReactiveX#2297
Adding @experimental tag because exposing reset() could be dangerous
Adding javadocs for `reset()` API.
Explicitly mentioning how caution is advised when using `reset()` API.
Also mentioning links to detailed discussions on github issue.

akarnokd added a commit that referenced this issue Apr 29, 2016

Making RxPlugins reset() public (#3820)
Discussions found here: #2297
Adding @experimental tag because exposing reset() could be dangerous
Adding javadocs for `reset()` API.
Explicitly mentioning how caution is advised when using `reset()` API.
Also mentioning links to detailed discussions on github issue.
@akarnokd

This comment has been minimized.

Show comment
Hide comment
@akarnokd

akarnokd May 5, 2016

Member

Closing via #3820

Member

akarnokd commented May 5, 2016

Closing via #3820

@Alisunov

This comment has been minimized.

Show comment
Hide comment
@Alisunov

Alisunov May 12, 2016

I'm getting problem when I use:
@ClassRule public static final RxJavaPluginsResetRule pluginsReset = new RxJavaPluginsResetRule();
instead of:
@Rule public final RxJavaPluginsResetRule pluginsReset = new RxJavaPluginsResetRule();

@ClassRule causes (singleExecutionHook.get() == null) to be true in RxJavaPlugins.getSingleExecutionHook() which leads to default hook for RxJavaPlugins.

How can it be possible?
Thanks!

I'm getting problem when I use:
@ClassRule public static final RxJavaPluginsResetRule pluginsReset = new RxJavaPluginsResetRule();
instead of:
@Rule public final RxJavaPluginsResetRule pluginsReset = new RxJavaPluginsResetRule();

@ClassRule causes (singleExecutionHook.get() == null) to be true in RxJavaPlugins.getSingleExecutionHook() which leads to default hook for RxJavaPlugins.

How can it be possible?
Thanks!

@Obaied

This comment has been minimized.

Show comment
Hide comment
@Obaied

Obaied Apr 10, 2017

Not sure if its related to this issue, but just wanted to say that RxJava2 changed a few things about how to override schedulers. I found another way outlined here: http://stackoverflow.com/a/43320828/3870025

Obaied commented Apr 10, 2017

Not sure if its related to this issue, but just wanted to say that RxJava2 changed a few things about how to override schedulers. I found another way outlined here: http://stackoverflow.com/a/43320828/3870025

dreynaud added a commit to spinnaker/spinnaker-dependencies that referenced this issue Apr 23, 2018

chore(*): rxJava 1.3.8
This is the latest in the 1.x rxJava branch, now EOL'ed.

The primary driver for updating is the fix for this issue:
ReactiveX/RxJava#2297 (comment)

@dreynaud dreynaud referenced this issue in spinnaker/spinnaker-dependencies Apr 23, 2018

Merged

chore(*): rxJava 1.3.8 #172

dreynaud added a commit to spinnaker/spinnaker-dependencies that referenced this issue Apr 23, 2018

chore(*): rxJava 1.3.8 (#172)
This is the latest in the 1.x rxJava branch, now EOL'ed.

The primary driver for updating is the fix for this issue:
ReactiveX/RxJava#2297 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment