Async await assignment - scala

I was looking over some Scala server code and I saw thins async/await block:
async {
while (cancellationToken.nonCancelled) {
val (request, exchange) = await(listener.nextRequest)
respond(exchange, cancellationToken, handler(request))
}
}
How can this be correct syntax?
As I understand it:
For every execution of the while loop
Thread 1 will execute the code from the while loop except the one in the await clause.
Thread 2 will go in the await clause.
But then Thread 1 will have val (request, exchange) uninstantiated in case Thread 2 doesn't finish computing.
These values will be passed to the respond and handler methods uninstantiated.
So how can you have an assignment in two different threads?

So how can you have an assignment in two different threads?
async-await's main goal is to allow you to do asynchronous programming in a synchronous fashion.
What really happens is that the awaited call executes listener.nextRequest and asynchronously waits for it's completion, it doesn't execute the next line of code until then. This guarantees that if the next line of code is executed, it's values are populated. The assignment should happen where it is visible to the next LOC in the method.
This is possible due to the fact that the async macro actually transforms this code into a state-machine, where the first part is the execution up until the first await, and the next part is everything after.

Related

Flutter: can l call the same Future, first with "then()" followed by "await", without incurring in race condition issues?

I came across this piece of code on SO:
EDIT:the following code snippet is fully functional, I'm trying to understand if beside "working", can it lead to errors due to a possible race condition
if (!_downloaders.containsKey(page)) {
_downloaders[page] = NetworkProvider().getRecentPodcasts(page);
_downloaders[page].then((_) => _downloaders.remove(page));
}
final podcasts = await _downloaders[page];
and I cannot wrap my head around one part:
_downloaders[page].then((_) => _downloaders.remove(page));
here after we added a future to this Map, we execute the future by calling then(),
because we want that after the future has finished, the future is removed from the Map.
Here all is clear, but on the next line, we call await, on the Future that has been added to the Map, and which will be removed soon.
I cannot really understand how this is good code, as it looks to me that when the Future is called with the then(), I know that the code execution doesn't stop for the then() (but it does for await) , but isn't there a remote case where it might get to the await part, but the future is NOT inside the Map anymore, as it has been already removed?
Or this can never happen, and if so, can you explain me the inner workings, so I can fully graps this concept and improve my codebase
I cannot really understand how this is good code, as it looks to me that when the Future is called with the then(), I know that the code execution doesn't stop for the then() (but it does for await) , but isn't there a remote case where it might get to the await part, but the future is NOT inside the Map anymore, as it has been already removed?
Future.then() does not execute the Future's computation. Future.then() only registers a callback.
The cited code usually shouldn't be racy. Futures are normally asynchronous; even if the Future's computation is already complete, the .then() callback will not execute until the Dart runtime returns to the event loop, which in this case would happen at the await line. You can observe this:
void main() async {
print('Constructing Future');
var future = Future.sync(() => print('Ran future'));
print('Constructed Future; registering callback');
// ignore: unawaited_futures
future.then((_) => print('Ran .then() callback'));
print('Registered callback; awaiting');
await future;
print('Done');
}
which will print:
Constructing Future
Ran future
Constructed Future; registering callback
Registered callback; awaiting
Ran .then() callback
Done
It's possible (but unlikely) that the code could be racy in pathological cases. For example, Flutter provides a SynchronousFuture class that implements the Future interface but executes its .then() callback synchronously upon registration. However, that is rather unusual (and which is why the documentation for SynchronousFuture explicitly discourages using it). For that to happen, the NetworkProvider().getRecentPodcasts implementation would have to explicitly return a SynchronousFuture (or some equivalent implementation).

Scala - differents between eventually timeout and Thread.sleep()

I have some async (ZIO) code, which I need to test. If I create a testing part using Thread.sleep() it works fine and I always get response:
for {
saved <- database.save(smth)
result <- eventually {
Thread.sleep(20000)
database.search(...)
}
} yield result
But if I made same logic using timeout and interval from eventually then it never works correctly ( I got timeouts):
for {
saved <- database.save(smth)
result <- eventually(timeout(Span(20, Seconds)), interval(Span(20, Seconds))) {
database.search(...)
}
} yield result
I do not understand why timeout and interval works different then Thread.sleep. It should be doing exactly same thing. Can someone explain it to me and tell how I should change this code to do not need to use Thread.sleep()?
Assuming database.search(...) returns ZIO[] object.
eventually{database.search(...)} most probably succeeds immediately after the first try.
It successfully created a task to query the database.
Then database is queried without any retry logic.
Regarding how to make it work:
val search: ZIO[Any, Throwable, String] = ???
val retried: ZIO[Any with Clock, Throwable, Option[String]] = search.retry(Schedule.spaced(Duration.fromMillis(1000))).timeout(Duration.fromMillis(20000))
Something like that should work. But I believe that more elegant solutions exist.
The other answer from #simpadjo addresses the "what" quite succinctly. I'll add some additional context as to why you might see this behavior.
for {
saved <- database.save(smth)
result <- eventually {
Thread.sleep(20000)
database.search(...)
}
} yield result
There are three different technologies being mixed here which is causing some confusion.
First is ZIO which is an asynchronous programming library that uses it's own custom runtime and execution model to perform tasks. The second is eventually which comes from ScalaTest and is useful for checking asynchronous computations by effectively polling the state of a value. And thirdly, there is Thread.sleep which is a Java api that literally suspends the current thread and prevents task progression until the timer expires.
eventually uses a simple retry mechanism that differs based on whether you are using a normal value or a Future from the scala standard library. Basically it runs the code in the block and if it throws then it sleeps the current thread and then retries it based on some interval configuration, eventually timing out. Notably in this case the behavior is entirely synchronous, meaning that as long as the value in the {} doesn't throw an exception it won't keep retrying.
Thread.sleep is a heavy weight operation and in this case it is effectively blocking the function being passed to eventually from progressing for 20 seconds. Meaning that by the time the database.search is called the operation has likely completed.
The second variant is different, it executes the code in the eventually block immediately, if it throws an exception then it will attempt it again based on the interval/timeout logic that your provide. In this scenario the save may not have completed (or propagated if it is eventually consistent). Because you are returning a ZIO which is designed not to throw, and eventually doesn't understand ZIO it will simply return the search attempt with no retry logic.
The accepted answer:
val retried: ZIO[Any with Clock, Throwable, Option[String]] = search.retry(Schedule.spaced(Duration.fromMillis(1000))).timeout(Duration.fromMillis(20000))
works because the retry and timeout are using the built-in ZIO operators which do understand how to actually retry and timeout a ZIO. Meaning that if search fails the retry will handle it until it succeeds.

Difference between Await.result and futures.onComplete in Scala

I am using the following two code snippets to execute code in multiple threads. But I am getting different behaviour.
Snippet 1:
val futures = Future.sequence(Seq(f1, f2, f3, f4, f5))
futures.onComplete{
case Success(value) =>
case Failure(value) =>
}
Snippet 2:
Await.result(Future.sequence(Seq(f1, f2, f3, f4, f5)), Duration(500, TimeUnit.SECONDS))
In futures I am just setting some property and retrieving the result.
Note: knowing only the behaviour difference between above two snippets is sufficient.
onComplete runs on some arbitrary (unspecified) thread in the ExecutionContext, whereas Await.result runs on the current thread, and blocks it until it completes or the specified timeout is exceeded. The first is non-blocking, the second is blocking.
There's also a difference in how failures are handled in the two snippets, but this is kind of obvious from looking at the code.
Actually future.onComplete register a call back and wait for the result as soon as the future got completed control goes inside to the future, and see what the future has inside, it could be either success or failure.
On the other hand the Await blocks the thread on which the future is running until the future got completed for specific timeout.
Hence the onComplete is non blocking and Await is blocking in the nature.
If you want to use await then try collecting as much as future you can and then do Await once you should not use Await for each and every future you have In the code it will rather slow your code.

Using future callback inside akka actor

I've found in Akka docs:
When using future callbacks, such as onComplete, onSuccess, and onFailure, inside actors you need to carefully avoid closing over the containing actor’s reference, i.e. do not call methods or access mutable state on the enclosing actor from within the callback.
So does it mean that i should always use future pipeTo self and then call some functions? Or i can still use callbacks with method, then how should i avoid concurrency bugs?
It means this:
class NotThreadSafeActor extends Actor {
import context.dispatcher
var counter = 0
def receive = {
case any =>
counter = counter + 1
Future {
// do something else on a future
Thread.sleep(2000)
}.onComplete {
_ => counter = counter + 1
}
}
}
In this example, both the actor's receive method, and the Future's onComplete change the mutable variable counter. In this toy example its easier to see, but the Future call might be nested methods that equally capture a mutable variable.
The issue is that the onComplete call might execute on a different thread to the actor itself, so its perfectly possible to have one thread executing receive and another executing onComplete thus giving you a race condition. Which negates the point of an actor in the first place.
Yes, you should send a message to the enclosing actor if the callback mutates internal state of the actor. This is the easiest (and preferred) way to avoid races.
I think I would be remiss if I did not mention here that I've made a small utility for circumventing this limitation. In other words, my answer to your question is No, you shouldn't use such an inconvenient workaround, you should use https://github.com/makoConstruct/RequestResponseActor
how does it work?
Basically, behind the futures and the promises, it transmits every query in a Request(id:Int, content:Any), and when it receives Response(id, result) it completes the future that corresponds to id with the value of result. It's also capable of transmitting failures, and as far as I can tell, akka can only register query timeouts. The RequestResponseActor supplies a special implicit execution context to apply to callbacks attached to the futures waiting for a Response message. This blunt execution context ensures they're executed while the Response message is being processed, thus ensuring the Actor has exclusive access to its state when the future's callbacks fire.
Maybe this can help. It is an experiment I did and the test is quite conclusive... however, it is still an experiment, so do not take that as an expertise.
https://github.com/Adeynack/ScalaLearning/tree/master/ActorThreadingTest/src/main/scala/david/ActorThreadingTest
Open to comments or suggestions, of course.
Futures with actors is a subject I am very interested in.

async ( with non-async) function control flow clarification?

( I've read a lot about async and I wonder what happens if there is a mix of async function call and non-async) and im talking about THREAD pov .
( I know that mix should not be done , but im asking in order to understand the flow better)
suppose I have(cube 1) function which calls async functions which calls asyc function.
(please notice that cube 1 function is not async)
Question : when the control reaches (cube 3) await Task.Delay(100); --
what is really happening as the control reaches cube3 await ? does the control is back(and blocked) at the pink arrow (cube 1 ) or does the control is released and still awaits ( orange arrow)
When control reaches the await statement in Cube3, Task.Delay() is called and immediately returns a Task that will complete after the delay. The rest of CalculateAnswer() is refactored into a continuation that will run when the Task returned by Delay() completes, and CalculateAnswer() immediately returns a Task<int> that will complete when that continuation completes.
CallCalculateAnswer() awaits the Task<int> returned by CalculateAnswer(), so the same logic applies: the code running after the await (i.e. the return statement) is refactored into a continuation that will run when the Task<int> completes, and CallCalculateAnswer() proceeds to return its own Task<int>.
StartChain(), however, does not await the Task<int> produced by CallCalculateAnswer(), so no continuation is generated. Instead, it stores the task into a local variable and returns. Therefore, the orange arrow in your question is the right one.
Note that, in this specific case, since nothing is done with the Task<int> returned by CallCalculateAnswer() and it is only stored in a local variable, it becomes "forgotten" once StartChain() returns: the task will complete (or fail) some time in the future, but its result (the int it produces) will be lost.
Update following comments: The pink arrow in your question implies you're expecting StartChain() to block, waiting for the task returned by CallCalculateAnswer() to complete, because it is not async and does not await that task. This is not what happens, as the usual control flow semantics apply: the method has returned a task, so you get a reference to that task and nothing more.
If you want StartChain() to block, you can use Task.Wait(), Task<T>.Result, or similar on the task returned by CallCalculateAnswer().