This question already has an answer here:
Karate framework retry until not working as expected
(1 answer)
Closed 1 year ago.
I have a scenario to conditional wait for every 5 secs for max 1 min. And I have implemented it via polling using java.lang.Thread.sleep(), which is blocking the Threads and failing in my multithread project. How can I use something like karate.pause() in my normal karate feature functions? Note: I can't use "retry until" in my case.
This is the method I use for polling with Thread.sleep(),
* def checkForEventCompletion =
"""
function(arg) {
var poolTime = 5;
var counter = 1;
// should pool for every 5 seconds until it exceeds your input wait time
while (true) {
if( (counter*poolTime) > arg.maxWaitTime){
karate.log('Status Not yet Updated');
return EventStatus;
}
//Code to Fetch EventStatus
karate.log('Current Status->',EventStatus);
if (EventStatus == 'COMPLETED') {
karate.log('Status Verified, --Exiting--');
return true;
}
// pool every 5 seconds
java.lang.Thread.sleep(poolTime*1000);
counter++;
}
}
When I try to use karate.pause(), it fails with "invokeMember (pause) on com.intuit.karate.core.ScenarioBridge#4acb7ecc failed due to: Unknown identifier: pause".
Most likely because you are using an old version of Karate and pause() is only in 1.1.0.
And I think you have confused a lot of things, pause() is only for performance-testing using Gatling: https://github.com/intuit/karate/issues/1622
If you are looking for testing async flows, please refer this: https://twitter.com/KarateDSL/status/1417023536082812935
The above example gives you an way to "wait" or poll for something. An alternate way is this: https://stackoverflow.com/a/55823180/143475
Else - your question does not make sense, so please provide more info after following this process: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue
And you can find an example of someone doing this here: https://github.com/intuit/karate/issues/1681
Related
I've seen some questions/answers very similar but none exactly describing what I would like to achieve. Some background, this is a multi step provision flow. In pretty short words this is the goal.
1. POST an action.
2. GET status based in one variable submitted above. If response == "done" then proceed. Returns an ID.
3. POST an action. Returns an ID.
4. GET status based on ID returned above. If response == "done" then proceed. Returns an ID.
5. (..)
I think there are 6/7 steps in total.
The first question is, are there any modules that could help me somehow achieve this? The only requirement is that each attempt to get status should have an X amount of delay and should expire, marking the flow as failed after an X amount of time.
Nevertheless, the best I could get to, is this, assuming for example step 2:
GetNewDeviceId : function(req, res) {
const delay = ms => new Promise((resolve, reject) => setTimeout(resolve, ms));
var ip = req;
async function main() {
let response;
while (true) {
try {
response = await service.GetNewDeviceId(ip);
console.log("Running again for: " + ip + " - " + response)
if (response["value"] != null) {
break;
}
} catch {
// In case it fails
}
console.log("Delaying for: " + ip)
await delay(30000);
}
//Call next step
console.log("Moving on for: "+ ip)
}
main();
}
This brings couple of questions,
I'm not sure this is indeed the best/clean way.
How can I set a global timeout, let's say 30 minutes, forcing it to step out of the loop and call a "failure" function.
The other thing I'm not sure (NodeJS newbie here) is that, assuming this get's called let's say 4 times, with different IP before any of those 4 are finished, NodeJS will run each call in each own context right? I quickly tested this and it seems like so.
I'm not sure this is indeed the best/clean way.
It am unsure whether your function GetNewDeviceId involves a recursion, that is, whether it invokes itself as service.GetNewDeviceId. That would not make sense, service.GetNewDeviceId should perform a GET request, right? If that is the case, your function seems clean to me.
How can I set a global timeout, let's say 30 minutes, forcing it to step out of the loop and call a "failure" function.
let response;
let failAt = new Date().getTime() + 30 * 60 * 1000; // 30 minutes after now
while (true) {
if (new Date().getTime() >= failAt)
return res.status(500).send("Failure");
try {...}
...
await delay(30000);
}
The other thing I'm not sure (NodeJS newbie here) is that, assuming this get's called let's say 4 times, with different IP before any of those 4 are finished, NodeJS will run each call in each own context right?
Yes. Each invocation of the function GetNewDeviceId establishes a new execution context (called a "closure"), with its own copies of the parameters req and res and the variables response and failAt.
How can I correctly perform something like sleep function using getTimer()? I need to do an action every 15 seconds. The code below doesn't work. I compile it with mtasc compiler on Linux.
class Tuto
{
static var lastMsg = 0;
static var msgInt = 15000;
static function main(mc)
{
if(getTimer() > lastMsg + msgInt)
{
trace("something");
lastMsg = getTimer();
}
}
}
The main instruction will be executed just once. You have to build some kind of loop or rely on the tick events sent by the player to execute your code continuously.
The basic options are:
while (true) { doSomething() }
this will execute forever, but remember that the flashplayer is single threaded so while that runs everything else will be frozen, UI and user inputs included. this is only "good" if you are building some heavy-processing tool that has no need of interacting with the user.
setInterval(doSomething, 15000)
this creates an interval that will call your function every X milliseconds. This is the simplest option and probably what you're looking for.
addEventListener(Event.ENTER_FRAME, doSomething)
this registers a listener for the ENTER_FRAME event of the Flash Player, which will be dispatched 30 times per second (by default). Inside that function you can check the current time with getTimer() and decide if it's time to execute your logic.
At first, I'm a newbie without experience in node js and would like to learn more. I wrote a delay function and I'm interessted, what you as a javascript professional think about it. What is good or bad on it and why?
I try to write a bot. It has 2 function. Function 1 starts function 2. But function 2 shall not start direct afterwards. It has to start with a delay.
Of course I made research for my topic and have found stuff like this:
How Can I Wait In Node.js (Javascript), l need to pause for a period of time
How to create a sleep/delay in nodejs that is Blocking?
Unfortunately I'm not able to understand and use it. Therefore I made my own try. It works on my computer, but should I bring it on a server?
//function 1 (example)
function start(){
...;
delay(2500, 'That could be an answer');
}
//Delay
function delay(ms, msg){
var started = new Date();
var now;
var diff = 0;;
while(diff < ms){
now = new Date();
diff = now - started;
console.log('Diff time: '+diff);
}
console.log('Delay started at: '+started);
console.log('Now time: '+now);
console.log('ms time: '+ms);
console.log('While loop is done.');
answer(msg);
}
//function 2 (example)
function answer(msg){
...
}
Thank's!
This is blocking.. your event loop will block executing this code. No other work will be done throughout the 2500 ms interval except for busy waiting inside the loop.
I'm not sure why you would want to do this. What you can do if you want to start function 2 at some point after function 1 is use setTimeout. This way, function 2 will be started after at least the time that you pass as argument to the setTimeout function while allowing other code to execute and not blocking the node event loop.
setTimeout(function(){
answer(msg);
}, 2500);
it does not work nevertheless. My delay time is more than an hour. Bute function 2 is executed after a couple of seconds.
setTimeout(function(){
answer(msg);
}, Math.floor(Math.random()*1000*87));
You can use bluebird promises with .delay to maintain your code more clean.
http://bluebirdjs.com/docs/api/promise.delay.html
Make your start function a promise then:
start().delay(2500).then(function (result) {
// result = start function return statment
});
TL;DR
What is the best way to forcibly keep a Node.js process running, i.e., keep its event loop from running empty and hence keeping the process from terminating? The best solution I could come up with was this:
const SOME_HUGE_INTERVAL = 1 << 30;
setInterval(() => {}, SOME_HUGE_INTERVAL);
Which will keep an interval running without causing too much disturbance if you keep the interval period long enough.
Is there a better way to do it?
Long version of the question
I have a Node.js script using Edge.js to register a callback function so that it can be called from inside a DLL in .NET. This function will be called 1 time per second, sending a simple sequence number that should be printed to the console.
The Edge.js part is fine, everything is working. My only problem is that my Node.js process executes its script and after that it runs out of events to process. With its event loop empty, it just terminates, ignoring the fact that it should've kept running to be able to receive callbacks from the DLL.
My Node.js script:
var
edge = require('edge');
var foo = edge.func({
assemblyFile: 'cs.dll',
typeName: 'cs.MyClass',
methodName: 'Foo'
});
// The callback function that will be called from C# code:
function callback(sequence) {
console.info('Sequence:', sequence);
}
// Register for a callback:
foo({ callback: callback }, true);
// My hack to keep the process alive:
setInterval(function() {}, 60000);
My C# code (the DLL):
public class MyClass
{
Func<object, Task<object>> Callback;
void Bar()
{
int sequence = 1;
while (true)
{
Callback(sequence++);
Thread.Sleep(1000);
}
}
public async Task<object> Foo(dynamic input)
{
// Receives the callback function that will be used:
Callback = (Func<object, Task<object>>)input.callback;
// Starts a new thread that will call back periodically:
(new Thread(Bar)).Start();
return new object { };
}
}
The only solution I could come up with was to register a timer with a long interval to call an empty function just to keep the scheduler busy and avoid getting the event loop empty so that the process keeps running forever.
Is there any way to do this better than I did? I.e., keep the process running without having to use this kind of "hack"?
The simplest, least intrusive solution
I honestly think my approach is the least intrusive one:
setInterval(() => {}, 1 << 30);
This will set a harmless interval that will fire approximately once every 12 days, effectively doing nothing, but keeping the process running.
Originally, my solution used Number.POSITIVE_INFINITY as the period, so the timer would actually never fire, but this behavior was recently changed by the API and now it doesn't accept anything greater than 2147483647 (i.e., 2 ** 31 - 1). See docs here and here.
Comments on other solutions
For reference, here are the other two answers given so far:
Joe's (deleted since then, but perfectly valid):
require('net').createServer().listen();
Will create a "bogus listener", as he called it. A minor downside is that we'd allocate a port just for that.
Jacob's:
process.stdin.resume();
Or the equivalent:
process.stdin.on("data", () => {});
Puts stdin into "old" mode, a deprecated feature that is still present in Node.js for compatibility with scripts written prior to Node.js v0.10 (reference).
I'd advise against it. Not only it's deprecated, it also unnecessarily messes with stdin.
Use "old" Streams mode to listen for a standard input that will never come:
// Start reading from stdin so we don't exit.
process.stdin.resume();
Here is IFFE based on the accepted answer:
(function keepProcessRunning() {
setTimeout(keepProcessRunning, 1 << 30);
})();
and here is conditional exit:
let flag = true;
(function keepProcessRunning() {
setTimeout(() => flag && keepProcessRunning(), 1000);
})();
You could use a setTimeout(function() {""},1000000000000000000); command to keep your script alive without overload.
spin up a nice repl, node would do the same if it didn't receive an exit code anyway:
import("repl").then(repl=>
repl.start({prompt:"\x1b[31m"+process.versions.node+": \x1b[0m"}));
I'll throw another hack into the mix. Here's how to do it with Promise:
new Promise(_ => null);
Throw that at the bottom of your .js file and it should run forever.
I am reading sample Hilo provided by MS, under ImageBrowserViewModel.cpp there is some code I am not understand:
// Observe the update after waiting the specified amount of time.
create_task([timeToWait]() {
assert(IsBackgroundThread());
::wait(timeToWait);
}).then([weakThis]() {
assert(IsMainThread());
auto vm = weakThis.Resolve<ImageBrowserViewModel>();
if (nullptr != vm)
{
vm->ObserveFileChange();
vm->m_hasFileUpdateTask = false;
}
}, task_continuation_context::use_current()).then(ObserveException<void>(m_exceptionPolicy));
The quest is app use IsBackgroundThread() & IsMainThread() to assert it should be correctly called under certain context. But for the ::wait(timeToWait) function call, there is no task_continuation_context defined to make sure it runs in background, I just wonder how does it make to work?? Thanks a lot!
The default for constructed tasks (as the first task is in your code snippet) is task_continuation_context::use_arbitrary(), so even though it is not specified this is what it will be. The task continuation lambda does assert this before calling ::wait (which would throw an exception if it attempted to run on the UI thread).