Dart timeout() does not seem to be triggering after specified duration - dart

I'm trying to wrap a function call in a retry and timeout. The retry below seems to be working fine, but the timeout() doesn't seem to be triggering as expected at all.
I've tried setting the ontimeout to print a message, throw an exception, throw a TimeoutException, and in all cases the expected timeout triggered. I've also tried adding a sleep() in the function being called to ensure that it takes longer then the timeout() duration.
await retry(
() => _sendUpdateTaskRequest(resultsJson).timeout(Duration(seconds: 5),
onTimeout: () => throw new Exception("ERRRR!")),
retryIf: (Exception e) =>
e is SocketException ||
e is TimeoutException ||
e is ClientException,
maxAttempts: requestRetryLimit,
);

lrn's comment was accurate. Changing the sleep to await Future.delayed(const Duration(seconds: 5)) was the correct course of action.

Related

Future's "then" runs even if there's no error to be caught in "catchError"

Code:
Future<int> _future() async => 1;
void main() {
_future()
.catchError((e) => print('catchError = $e'))
.then((value) => print('value = $value'));
}
AFAIK, catchError returns a new Future and then should run after catchError has run. But in above code, there's no error and hence catchError never runs, however then does run. Why is that so?
The documentation for Future.catchError states:
Returns a new Future that will be completed with either the result of this future or the result of calling the onError callback.
Doing someFuture.catchError(...).then(...) does not execute the then callback only if the catchError callback fires; it executes the then callback when the original Future completes or if the onError callback fires.

Difference between .then() and .whenCompleted() methods when working with Futures?

I'm exploring Futures in Dart, and I'm confused about these two methods that Future offers, .then() and .whenCompleted(). What's the main difference between them?
Lets say I want to read a .txt using .readAsString(), I would do it like this:
void main(){
File file = new File('text.txt');
Future content = file.readAsString();
content.then((data) {
print(content);
});
}
So .then() is like a callback that fires a function once the Future is completed.
But I see there is also .whenComplete() that can also fire a function once Future completes. Something like this :
void main(){
File file = new File('text.txt');
Future content = file.readAsString();
content.whenComplete(() {
print("Completed");
});
}
The difference I see here is that .then() has access to data that was returned!
What is .whenCompleted() used for? When should we choose one over the other?
.whenComplete will fire a function either when the Future completes with an error or not, instead .then will fire a function after the Future completes without an error.
Quote from the .whenComplete API DOC
This is the asynchronous equivalent of a "finally" block.
then runs if the future completes successfully.
catchError runs if the future fails.
whenComplete runs regardless of the future completed with a value or with an error.
Here's the basic flow:
someFuture().then((value) {
print('Future finished successfully i.e. without error');
}).catchError((error) {
print('Future finished with error');
}).whenComplete(() {
print('Either of then or catchError has run at this point');
});
.whenComplete = The function inside .whenComplete is called when this future completes, whether it does so with a value or with an error.
.then = Returns a new Future which is completed with the result of the call to onValue (if this future completes with a value) or to onError (if this future completes with an error)
Read detail on API DOC
whenComplete then

Is it ever useful to cancel an asyncio future?

I am trying to understand the use of Future.cancel() with asyncio. The Python documentation is very light on this. I've had no success with existing questions on here or search engines. I just want to understand happens when a task is awaiting a future which is cancelled.
Here is my code:
import asyncio
async def foo(future):
await asyncio.sleep(3)
future.cancel()
async def bar(future):
await future
print("hi")
async def baz(future):
await bar(future)
print("ho")
loop = asyncio.get_event_loop()
future = loop.create_future()
loop.create_task(baz(future))
loop.create_task(foo(future))
loop.run_forever()
"hi" is not seen printed. So I initially guessed bar was returning at the line await future in the case of a cancel.
However, "ho" is not printed either. So it seems logical that cancelling a future never yields back to tasks awaiting it? But then these tasks are sitting in the event loop forever? This seems undesirable, where have I misunderstood?
In this case the answer lies in the documentation, but you have to look for it a bit. First, a reminder of what it means to await a future:
# the expression:
x = await future
# is equivalent to:
... magically suspend the coroutine until the future.done() becomes true ...
x = future.result()
In other words, once the execution of the coroutine that contains await resumes, the value of the await statement will be the result() of the awaited future.
The question is: when you cancel a future, what is its result? The documentation says:
If the Future has been cancelled, this method raises a CancelledError exception.
So when someone cancel a future you awaited, the await future expression will raise an exception! This neatly explains why bar doesn't print hi (because await future has raised), and why baz doesn't print ho (because await bar(...) has raised).
A traceback is never printed because loop.create_task spawns the coroutine in the "background" (of sorts) - if no one inspects the return value, the exception will be lost. And since you threw away the task object returned by create_task and used run_forever to have the loop running forever, the loop just continues running, waiting (forever) for new tasks to somehow arrive.
If you changed the code to actually collect the result of bar, you would easily observe the CancelledError:
if __name__ == '__main__':
loop = asyncio.get_event_loop()
future = loop.create_future()
loop.create_task(foo(future))
loop.run_until_complete(baz(future))
Output:
Traceback (most recent call last):
File "xxx.py", line 19, in <module>
loop.run_until_complete(baz(future))
File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
return future.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 266, in result
raise CancelledError
concurrent.futures._base.CancelledError

How do I fail a script running in Bitbucket Pipelines?

When a pipeline runs a node series of commands, how can I trigger a fail within the pipeline?
I have tried the following:
const failBuild = function(message) {
console.error('Deploy failed: ', message)
throw new Error('Deploy failed')
}
I see the "Deploy failed" message, but the pipeline still says "Success".
Bb Pipelines fail when a command exits with a non-zero exit code. So, if you want the pipeline to fail, you have to make sure the code is not 0.
In your case (note for people reading this later: see comments), you get 0 as exit status, because the throw is executed in a promise, but then catched in the promise’s catch() function – which does neither stop execution nor have any influence on the exit code.
Solution: explicitly throw an error in the catch() function.
For anyone else who might be struggling with this...
You need to return a non zero as already mentioned, I find the easiest way to do this is by passing a negative integer to PHP's exit() function.
https://php.net/manual/en/function.exit.php
if($condition == true)
{
// Whatever we were doing, it worked YAY!!
exit();
}
else
{
// Something went wrong so fail the step in the pipeline
exit(-1);
}
The accepted answer states:
Solution: explicitly throw an error in the catch() function.
So if I understand that correctly, it suggests you should write the script as:
async function main() { throw "err"; }
main().catch(e => { throw e; });
However, this does not work: the exit code is still 0, and the console displays a nasty warning:
> node "main.js"
(node:32996) UnhandledPromiseRejectionWarning: err
(node:32996) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:32996) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
> $?
0
The correct way to bubble up the error to the node process is:
process.on('unhandledRejection', up => { throw up });
async function main() { throw "err"; }
main();
This way, you get teh following result:
> node "main.js"
test2.js:1
process.on('unhandledRejection', up => { throw up });
^
err
> $?
1
Which is a little bit better (except the stacktrace is not very clear).

If I want everything to execute, in order, inside a function, do I await each line?

I know for sure my brain isn't totally clear on async/await so I need some clarity. I see a lot of examples where await is used on some lines and not others inside a function marked async. For example, I rarely if ever have seen an example like this (I am using the print statement as an example of something simple/basic.):
myFunction() async {
await functionA();
await print("This really long thing that's going to print out.");
await functionB();
await MyExtraClass.lookupSomethingQuickly();
...
}
So the examples I see it's usually something like this:
myFunction() async {
await functionA();
print("This really long thing that's going to print out.");
await functionB();
MyExtraClass.lookupSomethingQuickly();
...
}
So I am wondering if there's just an assumption that simple things will complete in order or if theoretically, putting await in front of each line is what I should be doing in cases where I absolutely need line 1 to follow line 2 to follow line 3, etc... Like what if I absolutely need that print to finish before functionB() goes off?
Essentially I find myself making a judgment call on every line every time I am writing a function with async/await and I never know if my code is working because of good timing and luck or if there would ever be cases that would throw the execution off.
async / await is to make asynchronuos code easier to write, to read and to reason about. Synchronuos code doesn't need such support.
For async programming in Dart see also https://www.dartlang.org/docs/tutorials/futures/
If you take this code example
import 'dart:async' show Future;
void main() {
doSomethingAsync().then((_) => print('afterwards'));
print('at last');
}
Future doSomethingAsync() {
return new Future.delayed(const Duration(seconds: 1), () {
print('done something');
});
}
Try it in DartPad
which prints
at last
done something
afterwards
If you're not familiar with async execution this might be surprising
This is because code passed to Future.delayed() is executed with a delay of 1 second. The Future instance returned by doSomethingAsync() "completes" when the code in Future.delayed() has been executed.
In this line
doSomethingAsync().then((_) => print('afterwards'));
we call .then(...) on the Future returned by doSomethingAsync() and pass a closure (inline function) to .then(...). ((_) => print('afterwards')).
A feature of Future is that it calls the code passed to then(...) after it was completed (in our case when done something was printed after 1 sec delay).
So the execution goes something like
call doSomethingAsync() which schedules a call to print('done something) for later execution and returns a Future
call print('at last'); which just prints at last
after 1 second delay print('done something') is called
the Future returned from doSomethingAsync() is completed
the Future calls `(_) => print('afterwards')
main() ends.
When we use async / await the code looks like
import 'dart:async' show Future;
Future main() async {
await doSomethingAsync();
print('afterwards');
print('at last');
}
Future doSomethingAsync() {
return new Future.delayed(const Duration(seconds: 1), () {
print('done something');
});
}
Try it in DartPad
When run, the output is
done something
afterwards
at last
we also could use async / await in doSomethingAsync() but now we only focus on main()
Now the execution looks like
call doSomething() and wait for the returned Future to complete
print('done something') is executed and the Future completed
the execution of code after await continues
print('afterwards');
print('at last');
This is probably the behavior you expected.
To your original question. await is only necessary when a call returns a Future and you want the following code only be executed when the Future was completed. If the call doesn't return a Future there is nothing to wait for.
await print('xxx') is still valid code. This is to support functions that sometimes do some async work and return a Future but sometimes the don't have async work to do and execute the code immediately and just return afterwards. In this case there is nothing to wait for.
someTimesAsync() {
if(new DateTime.now().weekday == 1) {
return new Future.delayed(const Duration(seconds: 1), () {
print('done something');
});
} else {
print('done something');
}
}
await someTimesAsync();
works in both cases. If it wouldn't this would be cumbersome.
For more details about async / await see also https://www.dartlang.org/articles/await-async/

Resources