Scala 2 futures containing api calls race condition - api

I've defined some API calls in Futures that make API calls to Mashery and Stripe
val stripeFuture = Future { // api call }
val masheryFuture = Future { //api call }
For the stripeFuture -The main logic is to set the stripeCustomerId on a Client object within the onSuccess block
stripeFuture onSuccess {
//client.stripeCustomerId
}
I've wrapped up the API calls in a for-comprehension similar to the example in Futures and Promises
val apiCalls = for {
masheryInfo <- masheryFuture
stripeCustomer <- stripeFuture
}
There is a rollback if one of the API calls fail
apiCalls onFailure {
case pse: MasheryException => {
// delete stripe customer id
}
case e: StripeException => {
//delete mashery api key
}
The problem is when the call to Mashery fails 'masheryFuture', I want to rollback 'get the stripe id' from the Client object but there is a around a 1 second delay til that call finishes and it doesn't set the stripeCustomerId until it hits the onSuccess block so within the ase pse: MasheryException => { } block, client.getstripeCustomerId returns null.
Is there a way of getting around this race condition for both of the API calls

Use Future.andThen.
The doc:
Applies the side-effecting function to the result of this future, and
returns a new future with the result of this future.
This method allows one to enforce that the callbacks are executed in a
specified order.
for (f <- Future(x).andThen { y }) etc.
Update:
for (f <- Future(x) andThen {
case Success(x) => use(x)
case _ => // ignore
}) yield result

Related

Send upstream exception in SharedFlow to collectors

I want to achieve the following flow logic in Kotlin (Android):
Collectors listen to a List<Data> across several screens of my app.
The source-of-truth is a database, that exposes data and all changes to it as a flow.
On the first initialization the data should be initialized or updated via a remote API
If any API exception occurs, the collectors must be made aware of it
In my first attempt, the flow was of the type Flow<List<Data>>, with the following logic:
val dataFlow = combine(localDataSource.dataFlow, flow {
emit(emptyList()) //do not wait for API on first combination
emit(remoteDataSource.suspendGetDataMightThrow())
}) { (local, remote) ->
remote.takeUnless { it.isEmpty() }?.let { localDataSource.updateIfChanged(it) }
local
}.shareIn(externalScope, SharingStarted.Lazily, 1)
This worked fine, except when suspendGetDataMightThrow() throws an exception. Because shareIn stops propagating the exception through the flow, and instead breaks execution of the externalScope, my collectors are not notified about the exception.
My solution was to wrap the data with a Result<>, resulting of a flow type of Flow<Result<List<Data>>>, and the code:
val dataFlow = combine(localDataSource.dataFlow, flow {
emit(Result.success(emptyList())) //do not wait for API on first combination
emit(runCatching { remoteDataSource.suspendGetDataMightThrow() })
}) { (local, remote) ->
remote.onSuccess {
data -> data.takeUnless { it.isEmpty() }?.let { localDataSource.updateIfChanged(it) }
}
if (remote.isFailure) remote else local
}.shareIn(externalScope, SharingStarted.Lazily, 1)
I can now collect it as follows, and the exception is passed to the collectors:
dataRepository.dataFlow
.map { it.getOrThrow() }
.catch {
// ...
}
.collect {
// ...
}
Is there a less verbose solution to obtain the exception, than to wrap the whole thing in a Result?
I am aware that there are other issues with the code (1 API failure is emitted forever). This is only a proof-of-concept to get the error-handling working.

How to make several synchronuous call of rxjava Single

I have difficulties making sequential calls of RxJava Single observerable. What I mean is that I have a function that makes http request using retrofit that returns a Single.
fun loadFriends(): Single<List<Friend>> {
Log.d("msg" , "make http request")
return webService.getFriends()
}
and if I subscribe from several places at the same time:
loadFriends().subscribeOn(Schedulers.io()).subscribe()
loadFriends().subscribeOn(Schedulers.io()).subscribe()
I want that loadFriends() makes only one https request but in this case I have two http request
I know how to solve this problem in blocking way:
The solution is to make loadFriends() blocking.
private val lock = Object()
prival var inMemoryCache: List<Friends>? = null
fun loadFriends(): Single<List<Friend>> {
return Single.fromCallable {
if(inMemoryCache == null) {
synchronize(lock) {
if(inMemoryCache == null) {
inMemoryCache = webService.getFriends().blockingGet()
}
}
}
inMemoryCache
}
But I want to solve this problem in a reactive way
You can remedy this by creating one common source for all your consumers to subscribe to, and that source will have the cache() operator invoked against it. The effect of this operator is that the first subscriber's subscription will be delegated downstream (i.e. the network request will be invoked), and subsequent subscribers will see internally cached results produced as a result of that first subscription.
This might look something like this:
class Friends {
private val friendsSource by lazy { webService.getFriends().cache() }
fun someFunction() {
// 1st subscription - friends will be fetched from network
friendsSource
.subscribeOn(Schedulers.io())
.subscribe()
// 2nd subscription - friends will be fetched from internal cache
friendsSource
.subscribeOn(Schedulers.io())
.subscribe()
}
}
Note that the cache is indefinite, so if periodically refreshing the list of friends is important you'll need to come up with a way to do so.

How to throwError within map of observable (rxjs6, ng6)

my question is similar to this one How to throw error from RxJS map operator (angular), but I'm on angular6 with rxjs6 and I guess all is changed ;)
I want to know, how I could propagate an Error-Object within map of an observable to the subscribe OnError Part. I always end up in the OnNext Part.
Here is what I have so far:
Within a ng-component I have maybe the following method call
[...]
this.dataStreamService.execCall({ method : 'order_list',params : {}})
.subscribe( r => {
// here r provides the result data from http call
console.log("execCall result", r);
}, err => {
// HERE the "MAP ERROR OCCURED" Error should be occured as well,
// but in doesn't
console.log("execCall error",err);
});
[...]
The called service method looks like:
execCall(dataStreamCall: DataStreamCall): Observable<DataStreamResult> {
let apiURL = '<some API-URL>';
let params = dataStreamCall.params;
// do HTTP request (this.http calls an extra service handler which wraps
// the angular httpClient and the API errors there
// There is NO Problem with that part :)
let apiResult = this.http.post(apiURL, params);
// Build a new Observable from type "DataStreamResult"
let dsr : Observable<DataStreamResult> = apiResult
.pipe(
map( httpresult => {
if (httpresult['status'] == false){
// the http call was basically successful,
// but state in data is false
// *** THIS IS NOT PROPAGATE TO SUBSCRIBE OnERROR ***
throwError({'msg' : 'MAP ERROR OCCURED'});
// also tried as alternative
return throwError({'msg' : 'MAP ERROR OCCURED'});
} else {
// here the http call was successful
let d = new DataStreamResult();
d.result = httpresult;
return d;
}
}),
catchError( err => {
// error is bubble up from http request handler
return throwError(err);
})
);
return dsr;
}
Finally the Question:
How could manage, that the "throwError" within the piped "map" is propagated to subscribe "err => { ... }".
The actual behavior for:
throwError({..})
I ended up in the subscribe OnNext Part with r = undefined
If I use:
return throwError({..})
I also ended up in the subscribe OnNext Part where r is the throwError-Observable
Thx in Advance
Best Regards
throwError({'msg' : 'MAP ERROR OCCURED'}) will return an observable that, when subscribed to, will effect an error notification. That is, it will call the subscriber's error method.
In your snippet, you either call throwError and ignore the value. Or you return its return value from a project function passed to the map operator.
Neither will effect an error.
There is no subscriber in the first situation, because the return value is ignored. And, in the second situation, there is no subscriber because the map operator doesn't subscribe to what it receives from the project function - the map operator's project function can return anything; it doesn't have to return an observable.
To throw an error within map, use:
throw {'msg' : 'MAP ERROR OCCURED'};

unable to understand execution flow in lagom

I am following this tutorial - https://www.lagomframework.com/documentation/1.3.x/scala/ServiceImplementation.html
I created a logged service
//logged takes a ServerServiceCall as argument (serviceCall) and returns a ServerServiceCall.
//ServerServiceCall's compose method creates (composes) another ServerServiceCall
//we are returing the same ServerServiceCall that we received but are logging it using println
def logged[Request,Response](serviceCall:ServerServiceCall[Request,Response]) = {
println("inside logged");
//return new ServerServiceCall after logging request method and uri
ServerServiceCall.compose({
requestHeader=>println(s"Received ${requestHeader.method} ${requestHeader.uri}")
serviceCall
}
)}
I used logged as follows:
override def hello3 = logged(ServerServiceCall
{ (requestHeader,request) =>
println("inside ssc")
val incoming:Option[String] = requestHeader.getHeader("user");
val responseHeader = ResponseHeader.Ok.withHeader("status","authenticated")
incoming match {
case Some(s) => Future.successful((responseHeader,("hello3 found "+s)))
case None => Future.successful((responseHeader,"hello3 didn't find user"))
}
})
I expected that inside ssc would be printed first and then print in logged but it was opposite. Shouldn't the arguments passed to the function be evaluated first?
I got this. Why?
inside logged
Received POST /hello3
inside ssc
logged is a function that you've written that takes a ServiceCall and decorates it with its own ServiceCall. Later on, Lagom invokes the service call with the request header. You are logging inside logged at the point that the service call is decorated, before it has been returned to Lagom, and so before it has been invoked, that's why it gets invoked first. This might explain it:
def logged[Request, Response](serviceCall:ServerServiceCall[Request, Response]) = {
println("3. inside logged method, composing the service call")
val composed = ServerServiceCall.compose { requestHeader=>
println("6. now Lagom has invoked the logged service call, returning the actual service call that is wrapped")
serviceCall
}
println("4. Returning the composed service call")
composed
}
override def hello3 = {
println("1. create the service call")
val actualServiceCall: ServerServiceCall[Request, Response] = ServerServiceCall { (requestHeader, request) =>
println("7. and now the actual service call has been invoked")
val incoming:Option[String] = requestHeader.getHeader("user");
val responseHeader = ResponseHeader.Ok.withHeader("status","authenticated")
incoming match {
case Some(s) => Future.successful((responseHeader,("hello3 found "+s)))
case None => Future.successful((responseHeader,"hello3 didn't find user"))
}
}
println("2. wrap it in the logged service call")
val loggedServiceCall = logged(actualServiceCall)
println("5. return the composed service call to Lagom")
loggedServiceCall
}
The important thing to remember is that the invocation of the hello3 method is not the invocation of the service call, hello3 merely returns a ServiceCall that Lagom will use to invoke it.

trying to understand a code fragment of an article on socket.io and redis

I'm trying to understand an article here, and now everything is clear but one code fragment, mentioned on pre-last code block, with a total of 1 to 17 lines, and this fragment is from line 1 to 9:
app.use(function(req,res,next) {
redis.get(req.user.email, function(err, id) {
if (err) next(err);
req.emitToUser = function() {
var soc = id && io.to(id);
soc.emit.apply(soc, arguments);
}
});
});
and I think its some shortcomings in my javascript knowledge are the root cause.
My knowledge over this code fragment:
The 'apply' method will execute the 'emit' with 'soc' as 'this' value
and feeds the 'emit' method with 'arguments' (am I right here
please?)
socket.id is related to the email of socket owner, because id.to(id) is based on the fact that the socket.id is the room where every socket is joined with itself. Redis provides the key-value data structure that holds user email as key, and the value is the socket.id.
problems:
where 'arguments' is coming from?
what's the purpose of this code fragment?
Please make me clear.
There are some issues with this code, but the general idea is to define a method on the req object req.emitToUser() for every incoming request that will allow some other route handler later in the chain to use that method to emit to the user who make the request. This is a common desire to want to connect a currently connected socket.io connection to the user making the http request.
Let's look at each line here:
redis.get(req.user.email, function(err, id) {
Look up the req.user.email in the redis database to get a socket.io id associated with that email that has previously been saved in that redis database.
if (err) next(err);
If it wasn't found in redis, make this request fail with an error.
req.emitToUser = function() {
Assign a new method to the current req object so that other route handlers later in the chain can use that method.
var soc = id && io.to(id);
Look up the id value in socket.io to get the socket for that id. Technically io.to() doesn't return the socket, but it returns an object that you can call emit() on that will send to that socket.
soc.emit.apply(soc, arguments);
The role of soc.emit.apply(soc, arguments); is this:
Execute the soc.emit() method
Set the this value when executing that method to the soc object.
Set the arguments when executing that method to whatever the arguments were that were passed to req.emitToUser(x, y, z) when it was called.
Here's a more concrete example:
function fn(a, b, c) {
console.log(a, b, c);
}
fn.apply(null, [1, 2, 3]);
Using fn.apply(null, [1, 2, 3]); will be the same as:
fn(1, 2, 3);
Now, you'd likely never use .apply() in this exact way when the arguments are already known. The case for using it is when you have some arbitrary array that is passed to you (you don't know what's in it) and you want to pass those arguments along to some other function in the exact same order as they were given to you. That's what soc.emit.apply(soc, arguments); is doing. It's taking the arguments object (which is an array-like structure that represents the arguments that were passed to the parent function req.emitToUser() and passing those exact arguments on it sock.emit(). If you knew exactly how many arguments there would be, then you could hard-code that same code as this:
app.use(function(req,res,next) {
redis.get(req.user.email, function(err, id) {
if (err) next(err);
req.emitToUser = function(msg, data) {
var soc = id && io.to(id);
soc.emit(msg, data);
}
});
});
But, .apply() creates a more generic solution that will work regardless of how many arguments were passed to req.emitToUser() as it will just pass all the arguments on to soc.emit().
This line of code is a bit suspect:
var soc = id && io.to(id);
It appears to be trying to protect against there not being a proper id returned from redis earlier. But, if there's no id, then soc will not be a valid object and the following like of code:
soc.emit.apply(soc, arguments);
will throw. So, the id && io.to(id) isn't really providing the proper protection. It appears this should more likely be:
app.use(function(req,res,next) {
redis.get(req.user.email, function(err, id) {
if (err) next(err);
req.emitToUser = function() {
if (id) {
var soc = io.to(id);
soc.emit.apply(soc, arguments);
} else {
// not sure what you want here, perhaps return an error
// or throw a more meaningful exception
}
}
});
});