Friday, April 24, 2020

Google Add-on framework support for long-running process or polling support

Assume we have a GSuite Add-on,

a. Invoking a long-running process
b. Invoking an async process which we need to check status periodically

Both the above won't be directly supported within the Apps Script framework for GSuite Add-ons, given (a) script framework imposed limitations. 
Eg:- Script execution timeout, Trigger timeout
(b) limitation of embedding <script> tags within Add-on UI

These limitations are imposed to keep Add-ons responsive as well as secure by the framework. But if you are publishing your Apps Script project as a web app(not from the manifest as an Add-on) there are built-in APIs to poll as well as we can include our own custom scripts. Discussion related to this can be found here. 

Back to the topic, 
Overcome the script execution timeout,

If your AppsScript project is on the legacy Rhino runtime based framework upgrade it to use the latest V8 based framework.














With this you will gain approximately +30 seconds of more execution time, which now will be 60 seconds opposed to the 30 seconds earlier.

But if this is still not enough for your requirement, and you require to poll on the status periodically there is not soo sleek workaround to get over it.


pre-requisites:

You need to host a separate app(on a different service provider) to do the heavy lifting, the actual task completion can go beyond 2 seconds and also polling logic can be defined here itself.

As an example, I have the following snippet running to mock the actual long-running task which takes 5 minutes to respond


Then I have the following page hosted which is used by the AppsScript code, and this is invoking the above service(mock long running task) and respond back after 5 minutes.


Note: Make sure to replace <NGROK_URL> with the URL to the above service, at the same time, you can combine these two and house above timeout function within here itself.


To invoke this long-running service I'm to use `setOpenLink` class resides within the `CardService` provided by the AppsScript F/W.



There are a couple of things which we need to focus here during the creation of the `htmlUrl`
eg:- getRedirectURI(), generateNewStateToken, asyncCallback

getRedirectURI() is a simple function within the AppsScript which returns the redirect URI which we have to call once our long-running task is done.


function getRedirectURI() {
    return "https://script.google.com/macros/d/" + ScriptApp.getScriptId() + "/usercallback";
}

generateNewStateToken, returns a state token which can be used along with our callback.


function generateNewStateToken(callbackName, user_info) {
  return ScriptApp.newStateToken()
    .withMethod(callbackName)
    .withArgument("user_info", JSON.stringify(user_info))
    .withTimeout(3600)
    .createToken();
}

asyncCallback, is the implementation of our callback function, here success is a html file created within the AppsScript Project which indicates our long running process is completed.


function asyncCallback(data) {
    Logger.log("Inside asyncCallback: " + JSON.stringify(data));
    return HtmlService.createHtmlOutputFromFile("success");
}

Outcome: When you open the Add-on you will get the link button, which invokes the long-running task which is hosted on a different service.





















This should open a new browser-tab/popup based on your `setOpenAs` config and once the long-running process is completed this should automatically get updated and closed. Based on your `setOnClose` configuration Add-on UI might refresh too.

Note: This is the not soo sleek part which I have mentioned earlier in this post.

















Github link to the full AppsScript source will be published soon.

No comments:

Post a Comment