Is there a way to wait until method is completed?

I’m writing a code for script actions.
I want to get subtask’s gids after duplicating a task with subtasks.
So I worte a code below at the begining.

body = {
      "data": {
        "name": task.data.name,
        "include": ["notes","assignee","subtasks","attachments","tags","followers","projects","dependencies","parent"]
      }
    };
const newTask = await tasksApiInstance.duplicateTask(body, task_gid);

After that, I’ll confirm whether a duplication has finished.
I assume using jobsApiInstance.getJob() with loop like below.

i = 0;
while(i<10){
  const jobStatus = jobsApiInstance.getJob(......);
  if(jobStatus.data.status === "succeeded"){
    break;
  }
  i++;
}

But I’m worried about requiring a lot in a short time.
Is there a way to wait like timer?

1 Like

Hi @Tetsuo_Kawakami,

Yes, you’ll want to wait between each iteration of checking for successful completion of the job.

Try this code:

async function run() {
  const task = await tasksApiInstance.getTask(task_gid);
  body = {
      "data": {
        "name": task.data.name,
        "include": ["notes","assignee","subtasks","attachments","tags","followers","projects","dependencies","parent"]
      }
    };
  const jobInfo = await tasksApiInstance.duplicateTask(body, task_gid);
  await waitForJobCompletion(jobInfo.data.gid);
  log("The job finished!")
}

const sleep = ms => new Promise(res => setTimeout(res, ms));

async function waitForJobCompletion(jobId) {
  for (let i = 0; i < 10; i++) {
    const jobStatus = await jobsApiInstance.getJob(jobId);
    if (jobStatus.data.status === "succeeded") {
      return jobStatus;
    }
    if (i < 9) { // don't wait after the last attempt
      await sleep(5000); // wait 5 seconds before next iteration
    }
  }
  throw new Error("Timed out waiting for job");
}

// To function properly, the script must end with returning a Promise via run().
run();
2 Likes

@Phil_Seeman
thanks for your help!
I tried it.Unfortunately an error below occured.

 Encountered an error: {"name":"Error","message":"setTimeout is not supported in this environment","stack":"    at <anonymous> (eval.js)\n    at Promise (native)\n    at sleep (eval.js)\n    at waitForJobCompletion (eval.js:33)\n"}

That would mean Asana doesn’t allow us to use setTimeout().
I’ll find out another way.

That’s odd, it worked perfectly for me, including the setTimeout. Not sure why you’re getting that error.

@Phil_Seeman
Thanks for your reply.
Yes. That’s very weird.Which did you execute it in script actions or in your local env?
I run it in my phoenix env.
Anyway I’ll try again and struggle.

I ran it in script actions in my Phoenix environment!

@Mikhail_Melikhov any idea why it worked in my Phoenix script action but not @Tetsuo_Kawakami’s?

I noticed that sometimes it works and other times it doesn’t.
When it works, a job status is succeeded at the first iteration. So sleep() doesn’t run.

In the end, how can we wait in script action?
Does anyone have a solution for it?

Hi @Phil_Seeman TIL that native JS timers are indeed not allowed in action scripts.

Is it possible that the tests you ran succeeded simply because the job completed quickly enough that a sleep() function call wasn’t needed?

@Phil_Seeman
Please don’t be offended, but I turned off Solution check because the problem isn’t solved.

@Mikhail_Melikhov
It’s nice to meet you.I think it’s the first contact with you.
I think we should avoid requiring a lot in a short time to confirm a job status.
Do you have any idea to wait between each iteration in script action?

Ah, well Ok!

Yes that’s possible.

No worries!

I can think of a few other ideas for waiting, but I don’t know if any of them are supported in this particular environment so I think we should wait (no pun intended) for some guidance from Asana, who knows what can and can’t run here.

1 Like

“Helpful” guidance has arrived. Please try one or more of:

  • Pace back and forth in your office while repeatedly looking at your watch
  • Cue this (turn on sound)
  • Light up a cigarette; that always used to make the bus you were waiting for appear right away so it should hasten the script’s completion.

Sorry, @Tetsuo_Kawakami!

Larry

2 Likes

Hi @Tetsuo_Kawakami , it’s great to meet you, and thank you for highlighting such a valid use case.

@dbrdak identified a potential approach to simulate native timeouts, but before sharing, we’d like to confirm internally whether this is the most suitable solution. We’ll get back to this shortly with an update.

4 Likes

Chiming in to say I also had this issue (my code must not have ever invoked setTimeout while testing so I didn’t realize it wasn’t supported and then dropped the script on like 30 projects with thousands of tasks lol). Really looking forward to the (potential, hopefully) solution!

2 Likes

Hi everyone!

After checking with our developers, I can confirm that using a custom sleep / setTimeout function is supported. That said, please remember that script actions have a maximum runtime of 60 seconds. This limit is in place for security reasons – for example, to protect against mistakes such as infinite loops.

If your workflow requires more time, consider breaking down a complex rule into smaller rules that trigger each other. This can help separate your logic into multiple steps and avoid hitting the 60-second timeout.

Here’s an example of a simple sleep function shared by our developers:

const sleep = async (ms) => {
    log('Waiting...');
    const start = Date.now()
    let currentTime = Date.now()
    while(currentTime - start < ms){
        currentTime = Date.now()
    }
};
6 Likes

@dbrdak
Thank you for the solution.
I confirmed it on my side.It worked well!

4 Likes