I am developing an application that returns Multi<String>, I would like to make some modifications to it, so I have added some methods, but for some reason it does not enter the next method at all.
My other methods are working absolutely fine. Because I am able to collect it and add it to a List, but I want to do some execution asynchronously, so using this approach.
private final ManagedExecutor managedExecutor;
public void writeTo(StreamingInfo streamingInfo) {
streamingInfo
.getEvents()
.runSubscriptionOn(managedExecutor)
.subscribe()
.withSubscriber(
new Subscriber < String > () {
#Override
public void onSubscribe(Subscription s) {
System.out.println("OnSubscription Method");
System.out.println("ON SUBS END");
}
#Override
public void onNext(String event) {
System.out.println("On Next Method");
}
#Override
public void onError(Throwable t) {
System.out.println("OnError Method");
}
#Override
public void onComplete() {
System.out.println("On Complete Method");
}
});
}
I get the following output:
OnSubscription Method
ON SUBS END
Which means that your subscription is not working for some reason. If I do not add subscription and directly collect to List then everything works as expected. Can anyone suggest what am I doing wrong here?
This is because the underlying Reactive Streams specification that SmallRye Mutiny implements has a built-in backpressure mechanism. The client (in your case your subscriber) needs to request the next item manually from the producer (events) otherwise, no item is sent down the reactive pipeline.
You need to save the Subscription object you receive in the onSubscribe method and call its request(long) method when you can process next item(s):
.withSubscriber(
new Subscriber<String>() {
private Subscription subscription;
#Override
public void onSubscribe(Subscription s) {
System.out.println("OnSubscription Method");
System.out.println("ON SUBS END");
subscription = s;
subscription.request(1);
}
#Override
public void onNext(String event) {
System.out.println("On Next Method");
subscription.request(1);
}
#Override
public void onError(Throwable t) {
System.out.println("OnError Method");
}
#Override
public void onComplete() {
System.out.println("On Complete Method");
}
});
In SmallRye there is also an easier way to do this:
events
.onSubscription()
.invoke(() -> {
System.out.println("OnSubscription Method");
System.out.println("ON SUBS END");
})
.onItem()
.invoke(event -> System.out.println("On Next Method"))
.onFailure()
.invoke(t -> System.out.println("OnError Method"))
.onCompletion()
.invoke(() -> System.out.println("On Complete Method"))
.subscribe()
.with(value -> {});
Related
Once the new Object is been added in a pipeline i can see the value(obj.url) of the new Object being printed without getting executing the Flux part.
Note: If i restart my application, it able to read all the objects and executes completely.
Issue: Seems like flux.interval is not getting subscribed for the
new events.
The new real time value will be added into a Map<String, BaseSubscriber>
Once added it will invoke startPipeline() method where it get printed with a new value but it wont execute after that . So here the real time added objects wont be executed with getMessages() and doSomeTask() method.
class pipelineProcess extends BaseSubscriber<Data>{
private final XYZ obj;
#PostConstruct
public void startPipeline() {
log.info("New Objected read {} ",obj.getUrl())
Flux.interval(Duration.ofMillis(500))
.flatMapIterable(aLong -> getMessages())
.flatMap(message -> doSomeTask(message))
.subscribe(this);
}
}
#Override
protected void hookOnSubscribe(Subscription subscription) {
log.info("Hook on Subscribe called for {} : ",obj.getUrl());
request(1);
}
#Override
protected void hookOnNext(ScanRequestData next) {
log.info("Hook on Next called for {}: ", obj.getUrl());
request(1);
}
#Override
protected void hookOnError(Throwable throwable) {
log.error("hookOnError exception", throwable);
request(1);
}
#Override
protected void hookOnComplete() {
log.warn("The reactor pipeline of {} has been completed.", obj.getUrl());
}
#Override
protected void hookOnCancel() {
log.warn("The reactor pipeline of {} has been cancelled.", obj.getUrl());
}
}
Can anyone tell me how to overcome this issue
I have a reactor.core.publisher.Mono variable and want to subscribe to org.reactivestreams.Subscriber, though it seems not works. I cannot get Why onNext method never called? I see onSubscribe method called fine. I could be mistaken, but as Mono implements Publisher, subscriber should work. Right?
#Test
public void subscriberTest() {
Mono<String> m = Mono.just("Hello!");
Subscriber<String> s = new Subscriber<String>() {
#Override
public void onSubscribe(Subscription s) {
System.out.println("Subscription "+s);
}
#Override
public void onNext(String t) {
System.out.println("onNext "+t);
}
#Override
public void onError(Throwable t) {
System.out.println("Throwable "+t);
}
#Override
public void onComplete() {
System.out.println("onComplete");
}
};
m.subscribe(s);
Mono<String> m1 = Mono.just("Bye!");
m1.subscribe(System.out::println);
}
Though the variable m1 subscription with method reference works fine. Here console output:
Subscription reactor.core.publisher.StrictSubscriber#4b168fa9
Bye!
Here I expect to see Hello! phrase too.
https://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html#onSubscribe-org.reactivestreams.Subscription- Here it is stated that No data will start flowing until Subscription.request(long) is invoked.
I have a DisposableSubscriber to a Flowable. The Flowable runs for some timeUntilTimeout, but in some situations I need to kill it earlier. Right now I call .dispose() on the DisposableSubscriber but the Flowable continues to emit events. Eventually the Flowable times out and .doOnCancel() is called.
I have the following code:
private Disposable mDisposableSubscription = null;
public void start() {
mDisposableSubscription = getFlowable()
.timeout(timeUntilTimeout, TimeUnit.MILLISECONDS)
.subscribeWith(new DisposableSubscriber<T>() {
#Override
public void onComplete() {
}
#Override
public void onError(Throwable throwable) {
dispose();
}
#Override
public void onNext(T t) {
// Do something
}
});
}
public void stop() {
// Log "dispose"
mDisposableSubscription.dispose();
}
private Flowable<T> getFlowable() {
return Flowable.create(new FlowableOnSubscribe<T>() {
public void subscribe(FlowableEmitter<T> emitter) {
startSomeAsyncProcess();
}
}).doOnCancel(new Action() {
public void run() {
// Log "do on cancel"
stopSomeAsyncProcess();
}
});
}
Calling stop() to dispose of the DisposableSubscriber before the Flowable times out means events emitted by the Flowable are no longer handled, but the Flowable continues emitting events and the async process continues running. I was under the impression that calling .dispose() downstream of the Flowable kills the Flowable by calling .doOnCancel(), but this does not appear to be the case. What am I missing?
The flowable is getting disposed, but you are not checking it on your Flowable.create function, so what happens is that the startSomeAsyncProcess() ignores it and keeps going.
To solve the issue, you should check the emitter.isDisposed() flag to know if you should stop emitting.
Example:
Flowable<T> getFlowable() {
return Flowable.create(new FlowableOnSubscribe<T>() {
public void subscribe(FlowableEmitter<T> emitter) {
while(!emitter.isDisposed()) {
emitter.onNext(...);
}
}
});
}
If that startSomeAsyncProcess() function doesn't allow you to check the flag, surely there is some way to cancel it. Then you can attach a cancellable:
Flowable<T> getFlowable() {
return Flowable.create(new FlowableOnSubscribe<T>() {
public void subscribe(FlowableEmitter<T> emitter) {
startSomeAsyncProcess();
emitter.setCancellable(() -> stopSomeAsyncProcess());
// I don't remember if it's setCancellable() or setDisposable()
}
});
}
Update: the methods setCancellable(...) and setDisposable(...) should behave equally, they just take different arguments.
I am learning RxJava and am testing a scenario where I read data from a DB and then post it to a Queue. I just made a sample mock of the whole process but I don't seem to find the Observable working as I wanted it to ie. asynchronously.
This is my code:
package rxJava;
import java.util.ArrayList;
import java.util.List;
import rx.Observable;
import rx.Observer;
import rx.functions.Action1;
public class TestClass {
public static void main(String[] args) {
TestClass test = new TestClass();
System.out.println("---START---");
test.getFromDB().subscribe(new Observer<String>() {
#Override
public void onCompleted() {
System.out.println("Publish complete.");
}
#Override
public void onError(Throwable t) {
System.out.println(t.getMessage());
}
#Override
public void onNext(String s) {
test.publishToQueue(s).subscribe(new Observer<Boolean>() {
#Override
public void onNext(Boolean b) {
if (b) {
System.out.println("Successfully published.");
}
}
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable arg0) {
}
});
};
});
System.out.println("---END---");
}
public Observable<String> getFromDB() {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 30; i++) {
list.add(Integer.toString(i));
}
return Observable.from(list).doOnNext(new Action1<String>() {
#Override
public void call(String temp) {
if (temp.contains("2")) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
public Observable<Boolean> publishToQueue(String s) {
return Observable.defer(() -> {
try {
if (s.contains("7")) {
Thread.sleep(700);
}
System.out.println("Published:: " + s);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Observable.just(true);
});
}
}
Suppose I get a list from the DB asynchronously and want to post it to the queue,. I have used an Observable returned from getFromDB and have subscribed to it which mimics the data I get from DB. Every time I get the data from DB , I want to push it to a queue using publishToQueue which also returns an Observable. I wanted to make the queue call also asynchronous. Now on positive acknowledgement from the queue such as the Boolean which I am returning (Observable<Boolean>), I want to print something.
So basically I just want both the processes to be asynchronous. For every data from DB, I push it to the Queue asynchronously.
I have added Thread.sleep() in both the methods, db call and queue so as to mimic a delay and to test the asynchronous operations. I think this is what causing the problem. But I also tried Obseravable.delay() but that doesn't even produce any output.
Please help me understand how this works and how I can make it work as I want it to.
You have to specified subscribeOn value.
Observable.just("one", "two", "three", "four", "five")
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(/* an Observer */);
http://reactivex.io/documentation/operators/subscribeon.html
By default, RxJava is synchronous. It means that everything will be perform in the same thread (and the current thread), by default. You can perform tasks in another thread thanks to observeOn / subscribeOn methods, or using some operators that perform tasks in another job (because it use another scheduler, like delay, interval, ...)
In your example, you have to explitly set in which scheduler the subscription will pe performed. (here, in which thread Observable.from will emit your list)
test.getFromDb()
.subscribeOn(Schedulers.io())
.subscribe();
Then you can use the flatMap operator and calling your publishToQueue method. This method will be executed in the previous scheduler, but you can force it to use another scheduler, thanks to observeOn method. Everything after the observeOn method will be executed in another thread.
test.fromDb()
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.flatMap(l -> test.publishToqueue(l))
.subscribe();
In order to not repeat myself, I want to re-use a Subscriber variable between two observables. How do you do accomplish this? My current code below does not work, because after the subscriber is used once, it is unsubscribed and no longer works again. If I new a Subscriber instead of reusing a variable, my subscription works. I don't want to write the same code twice, if possible.
public class HomePresenter extends BasePresenter<HomeView> {
ArticleRepo articleRepo;
#Inject
public HomePresenter(ArticleRepo articleRepo) {
this.articleRepo = articleRepo;
}
#Override
public void onCreate(#Nullable PresenterBundle bundle) {
super.onCreate(bundle);
}
public void onEvent(ArticleCategoryClickedEvent event) {
Timber.v("Adapter position clicked at position: '%d'", event.getAdapterPosition());
view.launchArticleActivity(event.getArticleCategory());
}
public void onEvent(SeabeeOnlineExternalLinkClickedEvent event) {
view.launchExternalLink(event.getSeabeeOnlineExternalLink());
}
public void loadArticleImages() {
articleRepo.getArticleBuckets()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
public void refreshData() {
articleRepo.refreshAndSaveArticles()
.flatMap(new Func1<List<ArticleEntity>, Observable<List<ImageArticleCategoryEntity>>>() {
#Override
public Observable<List<ImageArticleCategoryEntity>> call(List<ArticleEntity> articleEntityList) {
return articleRepo.getArticleBuckets();
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
final Subscriber<List<ImageArticleCategoryEntity>> subscriber = new Subscriber<List<ImageArticleCategoryEntity>>() {
#Override
public void onCompleted() {
Timber.v("Loading article images complete!");
view.hideLoadingAnimation();
}
#Override
public void onError(Throwable e) {
Timber.e("Error loading article images", e);
Log.e("tag", "Error loading article images", e);
}
#Override
public void onNext(List<ImageArticleCategoryEntity> integerImageArticleCategoryEntityHashMap) {
view.loadArticleImages(integerImageArticleCategoryEntityHashMap);
}
};
}
A Subscriber should not be reused. It will not work because it is a Subscription and once unsubscribed it is done.
Use an Observer instead if you want to reuse it.
source
You can reuse your subscriber, you just need to create an actual class out of it.
private static class MySubscriber extends Subscriber<List<ImageArticleCategoryEntity>> {...}
Subscriber<> subscriber1 = new MySubscriber();
Subscriber<> subscriber2 = new MySubscriber();
And there you go.