1

I have a REST API coded with Node.js and there is one route that applies NTFS Rights to folders. The request can take 1 second but can also last several minutes (it depends on the size of the folder).

To summarize, if the rights take less than 5 seconds to be applied, I want to return the value with the code 200.

If the rights have not finished being applied I would like to return the value with the code 202

...

inProgress = true;
ApplyRights()
    .then(() => {
        inProgress = false
    }


// Here I want to return as fast inProgress = false otherwise wait a bit but max 5s

return ...;

I tried to wait a bit with setTimeout like this:

const sleep = s => new Promise(resolve => {
    setTimeout(resolve, s * 1000)
});

let nbCheck = 0;
while (inProgress && nbCheck < 5){
    await sleep(1)
    nbCheck++;
}

But setTimeout is not called before the end of my previous promise (ApplyRights). I read here that promise are executed before setTimeout

So, i tried to find a solution without setTimeout and I tried this: (I know it's not very elegant)

let dateStop = Date.now() + 5 * 1000;
while (dateStop = Date.now() && inProgress){}
return ...;

But in this case the .then() of ApplyRights is only reached at the end of the 5s.

Is there a way to let my promise ApplyRights do its job. And if the job take time, wait maximum 5 seconds before returning the response. If the job is quick, I want to return the responses without waiting.

halfer
  • 19,824
  • 17
  • 99
  • 186
jéjé
  • 15
  • 5

1 Answers1

0

You can use Promise.race:

Promise.race([ApplyRights(), sleep(5)]).then(result => {
    if (result === undefined) { // Timeout of 5 seconds occurred 
         // Some message to the user?
    } else { // Got reply within 5 seconds
         // Do something with the result
    }
});

Do realise however, that this does not interrupt the work of ApplyRights(), which eventually may still do the job.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Thanks for your help. But it only works if the answer took less than 5s. Because the setTimeout function is only executed when my promise ApplyRights is done and that's the problem. – jéjé May 05 '22 at 11:50
  • 1
    If `ApplyRights` is *synchronous*, then you have a problem. It should be a promise-returning function that does the hard work asynchronously. If this is not the case, you are out of luck: JS will be busy with it, and cannot do anything else. If you need help with designing `ApplyRights` to be asynchronous, you should dedicate a question on that. – trincot May 05 '22 at 12:16
  • 1
    If however `ApplyRights` returns immediately with a promise while the asynchronous request is pending, then `sleep` will be executed immediately, and it will work as expected. – trincot May 05 '22 at 12:19
  • `ApplyRights` is asynchronous. If i do this: `let promise = ApplyRights();` I get a **Promise { }** But `sleep` is not executed until `ApplyRights` is done. – jéjé May 05 '22 at 12:26
  • `sleep` gets executed when you get the `ApplyRights` promise back. Not when it resolves. – trincot May 05 '22 at 12:28
  • Here is what i do: `return Promise.race([ApplyRights(), sleep(5)]).then(result => { ... });` And with some console.log() here what I got: **1.Message from ApplyRights** **2.Message from sleep** And the result always comes from `ApplyRights` even if it take 30s – jéjé May 05 '22 at 12:39
  • 1
    That depends on when you send the message. But I 100% guarantee that `sleep()` is executed when `ApplyRights` returns (with a pending promise). If `ApplyRights` takes a long time to return its promise, then that is where you have a problem. – trincot May 05 '22 at 12:47
  • No `ApplyRights` didn't take a long time to return its promise. Because if I don't call the `sleep` function, I can directly return the response to the user. But doing so, I don't know if the rights is already applied or not. – jéjé May 05 '22 at 12:51
  • If `ApplyRights` takes 10ms to return its promise then `sleep` will be called 10ms after `ApplyRights` was called. If you have a problem, please provide code that reproduces the issue. If I replace `ApplyRights` with a simple promise that resolves 10 seconds later, then `Promise.race` resolves after 5 seconds. If it is different for you, please present code that reproduces the issue. A pitfall could be that `ApplyRights` resumes after an `await` and then performs a busy JS process that takes a long time to finish -- blocking the event loop. – trincot May 05 '22 at 12:55
  • 1
    Indeed if I replace `ApplyRights` with `sleep(10)` the response is returned after 5s correctly. `ApplyRights` performs quite complex operations. Including writes to the windows file system and applying rights with a C++ library. It probably blocks the event loop. So my problem is from this function. Thanks for your help. – jéjé May 05 '22 at 13:17