0

I have two functions that I want to run at the same time but I can't just let them run separately as one function contains an infinite loop while(true). And the problem with JavaScript is that if you where to run two functions, it will finish running the function before running the next one; so if I run a function with a while(true) loop, it will never move onto the next function.
If you still don't understand, here is my code:

function onOpen(){           // Google Apps Script trigger
    infLoop()                //how to run both of these functions at the same time?
    runScript()
}

function infLoop(){          //inf loop.

    while(True){
        Utilities.sleep(100)
        DocumentApp.getActiveDocument()
        .setname("dont change this name")
    }
}

function runScript(){
    //code...
}
TheMaster
  • 45,448
  • 6
  • 62
  • 85
Mr PizzaGuy
  • 410
  • 6
  • 19
  • 1
    Why? Use case`````````````````​````````````````` – TheMaster Sep 23 '19 at 15:14
  • 1
    Apps Script has a maximum script runtime limit https://developers.google.com/apps-script/guides/services/quotas, which will not allow you to run an infinite loop. As a workaround I suggest you to set-up a time-based trigger that will allow you to run your function in intervals of your choice: https://developers.google.com/apps-script/guides/triggers/installable – ziganotschka Sep 23 '19 at 15:52
  • 1
    For example, is this GAS library useful for your situation? https://github.com/tanaikech/RunAll – Tanaike Sep 23 '19 at 22:31
  • 1
    Another option would be gasThreader. See: https://sites.google.com/a/mcpher.com/share/Home/excelquirks/gasthreader and https://github.com/brucemcpherson/gasThreader – Magne Jun 17 '20 at 10:42

4 Answers4

13

Google apps script executes synchronously. For the most part, simultaneous/paralell processing is not possible. Based on your script, it seems you want two functions to run simultaneously onOpen. Possible workarounds(Some not tested):

Workaround#1: Use Different projects

  • Create a new project: In the editor(Legacy/Old editor only)>File>New>Project
  • First project's onOpen() will run infLoop()
  • Second project's onOpen() will run runScript()
  • Both functions will run simultaneously on open.

Workaround#2: Simple and Installable trigger1

  • Create a installable trigger for runScript()
  • Simple trigger onOpen() will run infLoop()
  • Both functions will run simultaneously on open.
  • You could use two installable triggers instead of simple and installable trigger.

Workaround#3: Web apps: Call from client

  • If there is a sidebar open or if a sheet is opened from web app, it is possible to call server functions repeatedly through google.script.run(which run asynchrously)

  • Here It is possible to run a function for 6 minutes(current runtime). But by repeatedly calling the server function, you can run the function for a long time(upto 90minutes/day = current trigger runtime quota/day)

Workaround#4: Web apps: UrlFetchApp#fetchAll2

  • UrlFetchApp#fetchAll runs asynchronously
  • Once a web app is published, the published url can be used with query parameters. If a function name is sent as a parameter and doGet() executes the function, .fetchAll can be used to multiple functions asynchronously.

Workaround#5: onEdit/onChange

  • If a edit is made, both functions(onEdit/onChange) run simultaneously.

Workaround#6: Sheets API/onChange

  • If a add-on/script makes a change through sheets api, onChange may get triggered. If triggered, every change made through sheets api causes onChange to run asynchronously.
TheMaster
  • 45,448
  • 6
  • 62
  • 85
  • Thank you!!! This helped a lot! I can see why you are "TheMaster". Though is there a way to make an infinite loop while avoiding the Script Timeout? – Mr PizzaGuy Sep 27 '19 at 15:05
  • 1
    @Mr.pizza Quotas will apply. There were talks about extending quotas to 30mins with v8. But it's in alpha stage currently. It might come by end of this year. Until then, I don't see hope.One way would be to use to time triggers every 6 minutes.. even then you're limited to a total quota of 90 minutes/day. – TheMaster Sep 27 '19 at 15:21
  • Thank you! I am using the time triggers like you have suggested. – Mr PizzaGuy Jan 12 '20 at 16:02
  • 1
    With regards to Workaround 4, you can use @Tanaike's excellent library with webapps but also without! The options are "Parallel processing with Web Apps" or "Parallel processing with the method of scripts.run of Google Apps Script API". https://github.com/tanaikech/RunAll – Magne Jun 10 '20 at 11:42
  • 1
    Another option would be gasThreader. See: https://sites.google.com/a/mcpher.com/share/Home/excelquirks/gasthreader and https://github.com/brucemcpherson/gasThreader – Magne Jun 17 '20 at 10:43
  • @Magne Looks like a nice library. Wish He explained the actual exploit though, which, on first look, just looks like #3, where there's a simultaneous execution limit of 30. – TheMaster Jun 17 '20 at 11:43
  • 1
    @TheMaster I know, I wish the same. What I found so far: "Gasthreader is a published Apps Script webapp" [1], which uses google.script.run to call it [2]. It seems to differ from Workaround #3 only in that you only need to call the web app / server once, and it will do the job of splitting the job into async parallel executions and merging the results back. [1] https://sites.google.com/a/mcpher.com/share/Home/excelquirks/gasthreader/structure [2] https://github.com/brucemcpherson/gasThreader/blob/5fd5b26e1b7573cfa7b9a4a2f331320249cc50df/Provoke.gs – Magne Jun 18 '20 at 10:31
  • @Magne Based on your links, It seems it's the same as #3 where the server is automatically called multiple times from the client using this library. – TheMaster Jun 18 '20 at 11:02
3

To run two or more functions "at the same time" you should call each function separately. One way is to use promises from client side code.

Bear in mind that your server-side infinite loop eventually will cause that your script exceed the maximum execution time (6 minutes / 30 minutes depending on the account type that effective user is using).

Related

Rubén
  • 34,714
  • 9
  • 70
  • 166
  • @StevendeSalas would say that [Promises don't actually execute asynchronously](https://stackoverflow.com/questions/31241396/is-google-apps-script-synchronous#answer-60174689), and TheMaster would [confirm](https://stackoverflow.com/questions/62806366/run-function-asynchronously-in-google-apps-script/62807671#62807671). – Dan Dascalescu Jul 09 '23 at 18:54
1

Running an infinite loop in Apps Script is futile, since there's an enforced maximum execution time of 6 minutes for most scripts. When you hit that limit the script execution will be killed.

Judging from your example script, what you're attempting to do is a scheduled job to set the document name. For that purpose, you would be better served using a time-driven trigger.

You could then structure your script like this:

function onOpen() {
    // code...
}

function updateDocumentName() {
    DocumentApp.getActiveDocument().setName("dont change this name")
}

Then, you can setup a time-driven trigger associated with the updateDocumentName() function.

One major difference to note: instead of executing the logic every 100ms, the highest frequency you can set with a time-driven trigger is once every 1 minute.

chuckx
  • 6,484
  • 1
  • 22
  • 23
-2

YES! Simply put one function inside the other.

function EmailSummary() {
  // Modified from http://stackoverflow.com/a/22200230/1027723 .. SOURCE: https://mashe.hawksey.info/2015/07/tips-on-emailing-inline-google-charts-from-sheets-using-apps-script/
  function emailCharts(sheet_name){    // eg "SF_EMAIL"
    sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheet_name)
    var charts = sheet.getCharts();

    if(charts.length==0){
      MailApp.sendEmail({

...

Just make sure to indent correctly.

Ace Pash
  • 1
  • 2
  • 5