Trying to insert in couchbase and that has observable return type but want mono,hence did this.
Its compiling but at run time its getting stuck forever at the conversion stage (i.e Mono.from { obs }).
fun saveScopeId(scopeId: ScopeId): Mono<ScopeId> {
val obs = scopeRepository.couchbaseOperations.insert(scopeId)
return Mono.from<ScopeId> { obs }
}
Observable can generate multiple values but if you can guarantee that it will be one item (I assume this is why you want to use Mono here) you can use Mono.fromDirect in this way:
Mono.fromDirect(yourObservable.toFlowable(BackpressureStrategy.BUFFER));
As you can see in example, there is toFlowable method used.
You should see the other backpressure strategies: here
This way we can achieve but not sure about the performance part.
As there Rx -> Rx -> Reactor conversion. Can someone tell me by looking into couchbase SDK 4.x (introduced recently), only if there are some conversion issue.
Mono.fromDirect(RxReactiveStreams.toPublisher(scopeRepository.couchbaseOperations.insert(scope)))
Try this but this thread blocking model.
public Mono<String> GetData(Observable<String> inputData) {
return Mono.fromCallable(() -> inputData.blockingFirst(""));
}
Related
I've created a reactive flow at my controller Endpoint addEntry where one object inside should be created only once per request since it holds a state.
#Override
public Mono<FileResultDto> addEntry(final Flux<byte[]> body,
final String fileId) {
return keyVaultRepository.findByFiletId(fileId)
.switchIfEmpty(Mono.defer(() -> {
final KeyVault keyVault = KeyVault.of(fileId);
return keyVaultRepository.save(keyVault);
}))
.map(keyVault -> Mono
.just(encryption.createEncryption(keyVault.getKey(), ENCRYPT_MODE)) // createEncryption obj. that holds a state
.cache())
.map(encryption -> Flux
.from(body)
.map(bytes -> encryption
.share()
.block()
.update(bytes) // works with the state and changes it per byte[] going through this flux
)
)
.flatMap(flux -> persistenceService.addEntry(flux, fileId));
}
before I asked this question I used
encryption.block() which was failing.
I found this one and updated my code accordingly (added .share()).
The test itself is working. But I am wondering if this is the proper way to go to work with an object that should be created and used only once in the reactive flow, provided by
encryptionService.createEncryption(keyVault.getKey(), ENCRYPT_MODE)
Happy to hear your opinion
Mono.just is only a wrapper around a pre-computed value, so there is no need to cache or share it, because it is only just giving back a cached variable on subscription.
But, in your example, there is something I do not understand.
If we simplify / decompose it, it gives the following:
Mono<KeyVault> vault = keyVaultRepository.findByFiletId(fileId)
.switchIfEmpty(Mono.defer(() -> keyVaultRepository.save(KeyVault.of(fileId));
));
Mono<Mono<Encryption>> fileEncryption = vault
.map(it -> Mono.just(createEncryption(it.getKey)).cache()); // <1>
Mono<Flux<Encryption>> encryptedContent = fileEncryption.map(encryption -> Flux
.from(body)
.map(bytes -> encryption
.share()
.block()
.update(bytes))); // <2>
Mono<FileResultDto> file = encryptedContent.map(flux -> persistenceService.addEntry(flux, fileId));
Why are you trying to wrap your encryption object ? The result is already part of a reactive pipeline. Doing Mono.just() is redundant because you are already in a map operation, and doing cache() over just() is also redundant, because a "Mono.just" is essentially a permanent cache.
What does your "update(bytes)" method do ? Does it mutate the same object every time ? because if it does, you might have a problem here. Reactive streams cannot ensure thread-safety and proper ordering of actions on internal mutated states, that is out of its reach. You might bypass the problem by using scan operator, though.
Without additional details, I would start refactoring the code like this:
Mono<KeyVault> vault = keyVaultRepository.findByFileId(fileId)
.switchIfEmpty(Mono.defer(() -> keyVaultRepository.save(KeyVault.of(fileId));
Mono<Encryption> = vault.map(it -> createEncryption(it.getKey()));
Flux<Encryption> encryptedContent = fileEncryption
.flatMapMany(encryption -> body.scan(encryption, (it, block) -> it.update(block)));
Mono<FileResultDto> result = persistenceService.addEntry(encryptedContent, fileId);
I have been trying for a long time to execute this code on Android, looking for answers here but not successfully. I'm a beginner developer, and please understand me.
I make multiple requests using Retrofit2 and RXJava
There is the answer, JSON (Array), it's class CurrencyData in Java
[
{
"r030":978,"txt":"euro","rate":11.11111,"cc":"EUR","exchangedate":"25.09.2018"
}
]
MyAPI interface
#GET("/BankService/v1/statdirectory/exchange")
Observable<List<CurrencyData>> getCurrencyCodeDate(#Query("valcode") String valCode, #Query("date") String date);
collect requests
List<Observable<List<CurrencyData>>> requests = new ArrayList<>();
requests.add(myApi.getCurrencyCodeDate("USD","20180928"));
requests.add(myApi.getCurrencyCodeDate("EUR","20180928"));
execute requests
Observable
.zip(requests, Arrays::asList)
.toList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
I got
[[CurrencyData{txt='Dollar USA', rate='1.111'}], [CurrencyData{txt='EURO', rate='2.222'}]]
I'm interested in how to get a List<CurrencyData> with all the CurrencyData objects.
I tried to use map and flatMap - but it does not work.
I will be very grateful.
Thank you.
Problem:
Your getCurrencyCodeDate method returns Observable of List<CurrencyData>, And you are using it inside a Observable.zip() whith zipper func as Arrays::asList.
What is happening is, Your getCurrencyCodeDate emits a List of objects and Arrays::asList is wrapping all the emitted Lists in a List. Resulting in Observable.zip() emitting List<List<>>.
On top of that .toList() operator is applied, which will again wrap emitted List<List<>> inside another List resulting in List<List<List<>>> as return type.
What you could do is, use merge operator instead of zip and use collectInto instead of toList.
Observable
.merge(requests)
.collectInto(new ArrayList<CurrencyData>(), ArrayList::addAll)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
In vertx guides, the sequential composition for chaining async calls is shown below:
FileSystem fs = vertx.fileSystem();
Future<Void> startFuture = Future.future();
Future<Void> fut1 = Future.future();
fs.createFile("/foo", fut1.completer());
fut1.compose(v -> {
// When the file is created (fut1), execute this:
Future<Void> fut2 = Future.future();
fs.writeFile("/foo", Buffer.buffer(), fut2.completer());
return fut2;
}).compose(v -> {
// When the file is written (fut2), execute this:
fs.move("/foo", "/bar", startFuture.completer());
},
// mark startFuture it as failed if any step fails.
startFuture);
Is it just me or is this code really cumbersome and hard to read?
There should be another way without falling into the callback hell.
It's a pity there are so few blog posts on vertx, any ideas are much appreciated.
these days the de facto library for writing asynchronous, non-blocking code on the JVM is RxJava. if you're not familiar i'd say it's highly worth your while to take a look as one of the many benefits is the ability to write "flows" as compositional streams that aren't quite as callback hell-y as the JDK's Futures were.
luckily, Vert.x is integrated with RxJava. as an example, here is your snippet rewritten using RxJava artifacts:
#Override
public void start(Future<Void> startFuture) throws Exception {
final FileSystem fs = vertx.fileSystem();
fs.rxCreateFile("/foo")
.andThen(fs.rxWriteFile("/foo", Buffer.buffer()))
.andThen(fs.rxMove("/foo", "/bar"))
.subscribe(
() -> {
startFuture.complete();
},
error -> {
startFuture.fail(error);
}
);
}
much more concise and readable.
note:
use RxJava 2 as it has superceded RxJava 1
...both versions, however, are supported in Vert.x, with their respective artifacts living in separate namespaces:
io.vertx.rxjava for version RxJava 1 artifacts
io.vertx.reactivex for version RxJava 2 artifacts
hope that helps!
Consider this example:
I have a file downloading in sequence. If one download fails, it should move to next.
Psudo code:
Observable.from(urls)
.concatMap(url -> downloadObservable(url))
There is no option for moving to next url if the download fails.
There is no way to skip with onErrorResumeNext() as I just want to move to next url. Can anyone help?
There is an operator for this: concatMapDelayError since 1.3. In general, if there is a reason errors could be delayed until all sources have been consumed fully, there is likely a opNameDelayError operator for it.
Observable.from(urls)
.concatMapDelayError(url -> downloadObservable(url))
.doOnError(error -> {
if (error instanceof CompositeException) {
System.out.println(((CompositeException)error).getExceptions().size());
} else {
System.out.println(1);
}
});
(The doOnError addendum comes from the updated OP's cross post on the RxJava issue list.)
If you are using RxJava 1, a quick and dirty solution is to return null when the download fails and then filter them out:
Observable
.from(urls)
.concatMap(url -> downloadObservable(url).onErrorReturn(null))
.filter(result -> result != null)
A nicer solution would be to create a wrapper for the result having a method like wasSuccessful() for checking in the filter and a method like getResult() for extracting the result from the wrapper. This way you don't have to handle nulls.
According to: https://github.com/ReactiveX/RxJava/issues/3870 there is no way to do this. Of course you can introduce some other error handling, i.e. handle error inside downloadObservable then filter null answers.
You have to think that is a pipeline so, in case you don't want to stop the emission of the pipeline, you have to control the error and return something in order to continue with the next emission.
The only way to use onErrorResumeNext and not stop the emission after that, is if it´s executed in a flatMap
Observable.from(urls)
.flatMap(url -> downloadObservable(url)
.onErrorResumeNext(t -> Observable.just("Something went wrong"))))
You can see an example here https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/errors/ObservableExceptions.java
I'm using rx.Observable all over my code and when I moved to a newer version of RxJava I have the need to switch to rx.Single.
Here is an example of how I use rx.Observable in my code:
obj.doSomething()
.filter(res -> {
return res.getStatus() == 0 ? true : false;
})
.subscribe(res -> {
handleResult(res);
});
With the new rxJava version, I had to change doSomething() to return rx.Single, so I can't use .filter() anymore making me handle its code in the .subscribe().
I don't like it so much because it was nice having a special .filter block that used to handle the control and in case of false it would NOT reach the .subscribe().
Any workaround or better design to avoid handling the boilerplate code in .subscribe()?