Possible to use Promise.in with infinite time? - promise

Is there a direct way to use Promise.in (or other sub/method/class) to achieve an indefinite amount of time? In other words the Promise is never resolved.
Currently I'm checking the $time when the promise is kept to see if an indefinite time was requested (indicated by negative or 0 value) and preventing the react block from exiting.
Is isn't a terrible solution, but is there are more idiomatic way of achieving this?
my $time=0;
react {
whenever Promise.in($time) {
#check if time is 0
done if $time > 0;
}
whenever signal(SIGINT) {
done;
}
#whenever Supply...{
#}
}

You can actually pass Inf to Promise.in, like this:
await Promise.in(Inf);
say "never happens";

whenever Promise.new {
pretty much gives you a promise that will never be kept, so the associated code will never fire. Not sure why you would do that, though.

If you want a promise that is never fulfilled, simply running Promise.new gives you one.
Somebody could still call .keep on that promise, unless you obtain a vow to prevent that.

Related

Cypress check that text either does not exist or is invisible

I want to check that a piece of text either does not even exist in the DOM or that if it exists, it is invisible.
cy.contains(text).should("not.visible) handles the second case, cy.contains(text).should("not.exist") the first, but either of them fails in the case of the other.
Before trying a conditional solution, have a read through this paragraph
https://docs.cypress.io/guides/core-concepts/conditional-testing#Error-Recovery
This is a feature that they intentionally made not available
Enabling this would mean that for every single command, it would recover from errors, but only after each applicable command timeout was reached. Since timeouts start at 4 seconds (and exceed from there), this means that it would only fail after a long, long time.
every cy...should has a built-in timeout, so if you have multiple your wait time would stack.
TL;DR;
If you can get around having to use a conditional, try that approach first
Alternatively, you can use this trick (at your peril 😉).
cy.get("body").then(($body) => {
if ($body.find(":contains(texta)").length > 0) {
cy.contains("texta").should("not.be.visible");
} else {
cy.contains("texta").should("not.exist");
}
});
cy.get("body").then(($body) => { will get the copy of body(DOM) in the current state and make it available for synchronous querying using jQuery. With jQuery we can determine synchronously whether an element contains the text string with $body.find(":contains(text)")
using the result's length you can make a condition that will then fire off cypress' asynchronous assertions.

Wrap a call in a task, to add a timeout?

We have an SDK that we are using from a 3rd-party. We have no access or insight into the code at all, or ability to change anything with it.
We're running into a problem where we make a bunch of updates to an object in the SDK, and then when we call their .Commit() method, it goes off into oblivion, and never comes back. Their Commit has no timeout parameter or anything to tell it - hey, give up already.
So when their code goes into oblivion, so too does our program.
I'm wondering if there is a way that I can use async/await stuff to essentially add a timeout to the call to their Commit. I've not done any of async stuff before though, so I'm not sure this is possible. I would still need it to be synchronous in terms of our program's process flow.
Essentially, I'm envisioning something along the lines of
... <setting a bunch of sdkObject fields> ...
var done = false;
await new Task(function(ref sdkObject, ref done) {
sdkObject.Commit();
done = true;
}, timeout: 60000);
if (done) {
<perform post-success code>
} else {
<perform post-failure code>
}
This then would allow us to artificially put a timeout around their Commit method, so that even if it goes off into oblivion, never to be seen again, our code would at least be able to try to wrap up gracefully and continue on with the next record to process.
I'm wondering if there is a way that I can use async/await stuff to essentially add a timeout to the call to their Commit.
Well... sort of.
You can wrap the call into a Task.Run and then use WaitAsync to create a cancelable wait, as such:
try {
await Task.Run(() => sdkObject.Commit()).WaitAsync(TimeSpan.FromSeconds(60));
<perform post-success code>
} catch (TimeoutException {
<perform post-failure code>
}
However, this will probably not work as expected. WaitAsync gives you a way to cancel the wait - it doesn't give you a way to cancel Commit. The Commit will just keep on executing - it's just that your application no longer cares if or when or how it complete.
The library you're using may or may not like having another Commit called when the last one is still running. So this may not actually work for your use case.
The only way to truly cancel uncancelable code is to wrap the code into a separate process and kill the process when you want to force cancellation. This is quite involved but sometimes you have no choice.

Cypress retries making test always pass

I am attempting to use the Cypress (at 7.6.0) retries feature as per https://docs.cypress.io/guides/guides/test-retries#How-It-Works
but for some reason it seems to be not working, in that a test that is guaranteed to always fail:
describe('Deliberate fail', function() {
it('Make an assertion that will fail', function() {
expect(true).to.be.false;
});
});
When run from the command line with the config retries set to 1,
npx cypress run --config retries=1 --env server_url=http://localhost:3011 -s cypress/integration/tmp/deliberate_fail.js
it seems to pass, with the only hint that something is being retried being the text "Attempt 1 of 2" and the fact that a screenshot has been made:
The stats on the run look also to be illogical:
1 test
0 passing
0 failing
1 skipped (but does not appear as skipped in summary)
Exactly the same behavior when putting the "retries" option in cypress.json, whether as a single number or options for runMode or openMode.
And in "open" mode, the test does not retry but just fails.
I am guessing that I'm doing something face-palmingly wrong, but what?
I think your problem is that you are not testing anything. Cypress will retry operations that involve the DOM, because the DOM takes time to render. Retrying is more efficient than a straight wait, because it might happen quicker.
So I reckon because you are just comparing 2 literal values, true and false, Cypress says, "Hey, there is nothing to retry here, these two values are never going to change, I'm outta here!"
I was going to say, if you set up a similar test with a DOM element, it might behave as you are expecting, but in fact it will also stop after the first attempt, because when it finds the DOM element, it will stop retrying. The purpose of the retry is to allow the element to be instantiated rather than retrying because the value might be different.
I will admit that I could be wrong in this, but I have definitely convinced myself - what do you think?
Found the cause .. to fix the problem that Cypress does not abort a spec file when one of the test steps (the it() steps) fails, I had the workaround for this very old issue https://github.com/cypress-io/cypress/issues/518 implemented
//
// Prevent it just running on if a step fails
// https://github.com/cypress-io/cypress/issues/518
//
afterEach(function() {
if (this.currentTest.state === 'failed') {
Cypress.runner.stop()
}
});
This means that a describe() will stop on fail, but does not play well with the retry apparently.
My real wished-for use case is to retry at the describe() level, but that may ne expensive as the above issue just got resolved but the solution is only available to those on the Business plan at $300/mo. https://github.com/cypress-io/cypress/issues/518#issuecomment-809514077

Why am I not allowed to break a Promise?

The following simple Promise is vowed and I am not allowed to break it.
my $my_promise = start {
loop {} # or sleep x;
'promise response'
}
say 'status : ', $my_promise.status; # status : Planned
$my_promise.break('promise broke'); # Access denied to keep/break this Promise; already vowed
# in block <unit> at xxx line xxx
Why is that?
Because the Promise is vowed, you cannot change it: only something that actually has the vow, can break the Promise. That is the intent of the vow functionality.
What are you trying to achieve by breaking the promise as you showed? Is it to stop the work being done inside of the start block? Breaking the Promise would not do that. And the vow mechanism was explicitly added to prevent you from thinking it can somehow stop the work inside a start block.
If you want work inside a start block to be interruptible, you will need to add some kind of semaphore that is regularly checked, for instance:
my int $running = 1;
my $my_promise = start {
while $running {
# do stuff
}
$running
}
# do other stuff
$running = 0;
await $my_promise;
Hope this made sense.
The reason why you cannot directly keep/break Promise from outside or stop it on Thread Pool are explained here in Jonathans comment.
Common misuse of Promises comes from timeout pattern.
await Promise.anyof(
start { sleep 4; say "finished"; },
Promise.in( 1 )
);
say "moving on...";
sleep;
This will print "finished". And when user realize that the next logical step for him is to try to kill obsolete Promise. While the only correct way to solve it is to make Promise aware that its work is no longer needed. For example through periodically checking some shared variable.
Things gets complicated if you have blocking code on Promise (for example database query) that runs for too long and you want to terminate it from main thread. That is not doable on Promises. All you can do is to ensure Promise will run in finite time (for example on MySQL by setting MAX_EXECUTION_TIME before running query). And then you have choice:
You can grind your teeth and patiently wait for Promise to finish. For example if you really must disconnect database in main thread.
Or you can move on immediately and allow "abandoned" Promise to finish on its own, without ever receiving its result. In this case you should control how many of those Promises can stack up in background by using Semaphore or running them on dedicated ThreadPoolScheduler.

Is the order of execution of resolved Awaitables well-defined in Hack?

The example below fires off 1000 async usleep calls separated by 100μs, then blocks the main thread before joining:
<?hh
$awaitable = HH\Asio\v((new Vector(range(1, 1000)))->map((int $wait_time) ==> {
return async {
await HH\Asio\usleep($wait_time*100);
echo $wait_time."\n";
};
}));
usleep(1000000);
HH\Asio\join($awaitable);
The result in stdout (3v4l) indicates the order that control returned to the async scopes.
The program consistently spits out a monotonically-decreasing sequence from 1000 to 1, suggesting that the finished Awaitables are pushed onto a stack and popped once the thread is freed in LIFO order. Is this ordering real, and can I rely on it?
This is deliberately not specified, and may change in the future -- and has already changed before. The only thing about async functions you can rely on is that after you await them then they have executed and returned their result.
(This also means, for example, that you should not rely on what happens when you invoke an async function but don't immediately await on it.)
If you rely in the exact ordering of Awaitables being collected or executed, you are probably doing something wrong.
Awaitables are supposed to be used for IO.
Could you explain a bit more why do you need exact ordering?
Yes, this ordering *is real, as ready await handles are explicitly processed in LIFO order. However, as #pablo-alcubilla writes, it shouldn't be relied on until it enters the HHVM spec, if ever.

Resources