AppsScriptPulse

Taming the Timeout: A Robust Webhook Strategy for Apps Script from Max Makhrov

Webhooks are a powerful way for developers to connect different applications, allowing them to automatically send data to a Google Apps Script project whenever an event occurs. However, this powerful technique comes with a significant challenge: if your script takes too long to process an incoming request, the sending service will time out, leading to lost data and unreliable automations.

In a recent article, Google Workspace Developer Max Makhrov shares a clever and effective architecture designed to make your webhooks both fast and reliable.

The Problem: When a Few Seconds is Too Long

The core issue is that services sending webhooks—like GitHubShopify, or Stripe—expect a nearly instant 200 OK response. These services have strict timeout policies, often between 5 to 10 seconds. If your doPost(e) function is busy with complex logic, writing to a spreadsheet, or making other API calls, it can easily fail to respond in time, causing the service to report a delivery failure.

The Solution: Cache Now, Process Later

Max’s approach decouples the initial reception of data from the heavy processing. The strategy is elegantly simple:

  1. Immediate Caching: The doPost(e) function is kept lean. Its only job is to immediately write the raw, incoming webhook data to Apps Script’s CacheService.
  2. Instant Response: With the data safely stored, the function quickly returns a success message, satisfying the sending service well within its required timeout window.
  3. Asynchronous Processing: A separate, time-driven trigger runs another function on a regular schedule (e.g., every minute). This function retrieves one or more tasks from the cache and performs the long-running processes.

To manage the tasks in the cache, Max introduces the concept of using a lightweight collection, which allows multiple webhook payloads to be queued and processed in an orderly fashion. Crucially, this pattern also uses LockService to prevent multiple processing functions from running simultaneously and trying to handle the same data.

While CacheService is perfect for this, it’s important to remember its limits: the 100KB size limit per item can be a challenge for webhooks with large payloads, and items expire after 10 minutes, so your processing trigger must run frequently enough to handle the workload.

It’s worth noting that this “fire and forget” pattern is ideal for notification-style webhooks, where the sending service only needs a 200 OK status to confirm receipt. For interactive webhooks that require a specific JSON response to be sent back immediately (like a Slack command), this asynchronous approach would not be suitable.

Here is a look at the lean doPost(e) function that captures the incoming data:

function doPost(e) {  
  try {  
    // Immediately write the raw payload to CacheService  
    writeHook2Cache\_(e);  
  } catch (err) {  
    // If caching fails, log the error  
    set2Memory\_(webhookKeys.error, err);  
  }  
  // Instantly return a 200 OK success response  
  return ContentService  
   .createTextOutput(JSON.stringify({status: 'success'}))  
   .setMimeType(ContentService.MimeType.JSON);  
}

This asynchronous architecture is a powerful pattern for any developer building robust integrations.

A big thank you to Max Makhrov for sharing this valuable technique with the community! You can find a more detailed explanation and links to the complete code on his Medium page.

Source: Using Collections for Handling Web-Hooks with App Script

Leave a Reply

Your email address will not be published. Required fields are marked *