Categories
Code

Google Pub/Sub Cron Job using Google Apps Script

This is a simple example of how you could use a Trigger in Google App Script (GAS) to launch (i.e. publish) a Pub/Sub message.

We cover the following:

  1. Create a new Google App Script
  2. Setup OAuth2
  3. Create a Service Account to use with the OAuth2
  4. Create a the REST call to Pub/Sub
  5. Setup the Trigger

We’ll use a Google Sheet to host our script. This makes the OAuth2 easier in that we could use a Sheet Sidebar to facilitate the authentication process.

Add the OAuth2 Library to you GAS script

More details on this is available here, but in short add a libary (Resources -> Libraries… ) using the following key:

1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF

Create a new file ( File -> New -> Script File ) and name it say service.gs with the following code:
function getService() {
  return OAuth2.createService('MyPubSub')
  .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
  .setTokenUrl('https://accounts.google.com/o/oauth2/token')
  .setClientId(CLIENT_ID)
  .setClientSecret(CLIENT_SECRET)
  .setCallbackFunction('authCallback')
  .setPropertyStore(PropertiesService.getUserProperties())
  .setScope(['https://www.googleapis.com/auth/cloud-platform','https://www.googleapis.com/auth/pubsub','https://www.googleapis.com/auth/script.external_request'])
  .setParam('access_type', 'offline')
  .setParam('approval_prompt', 'force')
  .setParam('login_hint', Session.getActiveUser().getEmail());
}function authCallback(request) {
  var service = getService();
  var isAuthorized = service.handleCallback(request);
  if (isAuthorized) {
    return HtmlService.createHtmlOutput('Success! You can close this tab.');
  } else {
    return HtmlService.createHtmlOutput('Denied. You can close this tab');
  }
}// Reset the service
function reset() {
  var service = getService();
  service.reset();
}var CLIENT_ID = '.....apps.googleusercontent.com';
var CLIENT_SECRET = '....';/**
* Logs the redirect URI to register.
*/
function logRedirectUri() {
  var service = getService();
  Logger.log(service.getRedirectUri());
}
Note that the Scope above is set to Pub/Sub as we will be sending a Pub/Sub REST request.

Create a Google Service Account

You need a CLIENT_ID and CLIENT_SECRET for the above.

This is a standard setup on the Google Cloud Console.

Goto the Google Cloud Console Credentials page -> Create credentials -> OAuth client ID -> Web application and ensure you populate the Authorised redirect URIs field with https://script.google.com/macros/d/[SCRIPT_ID]/usercallback where the SCRIPT_ID is specific to your Google App Script ( File -> Project Properties -> Script ID )

If this is the first time you create credentials you will need to setup the OAuth consent screen just follow the prompts.

Create the Pub/Sub Script

Create another script file ( File -> New -> Script file ) and add the following:

function pubsub(project, topic, attr, data) {
  var ss = SpreadsheetApp.getActive();
  var service = getService();
  
  if (!service.hasAccess()) {
    var authorizationUrl = service.getAuthorizationUrl();
    var template = HtmlService.createTemplate(
      '<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. ' +
      'Reopen the sidebar when the authorization is complete.');
    template.authorizationUrl = authorizationUrl;
    var page = template.evaluate();
    SpreadsheetApp.getUi().showSidebar(page);
    
  } else {
    var url = 'https://pubsub.googleapis.com/v1/projects/[PROJECT]/topics/[TOPIC]:publish'
    .replace("[TOPIC]", topic)
    .replace("[PROJECT]", project);
    
    // The data attribute is of 'string' type and needs to be base64 Encoded!
    var body = {
      messages: [
        {
          attributes: attr,
          data: Utilities.base64Encode(data)
        }]
    };    
    
    var response = UrlFetchApp.fetch(url, {
      method: "POST",
      contentType: 'application/json',
      muteHttpExceptions: true,
      payload: JSON.stringify(body),
      headers: {
        Authorization: 'Bearer ' + service.getAccessToken()
      }
    });
    
    var result = JSON.parse(response.getContentText());
    var message = JSON.stringify(result);
   return {
      log: message
    }
  } //end of if
}
You could now use a simple trigger to run your Pub/Sub cron job:

Our first trigger has been running for almost 7 years every 5 minutes. 🙂

Leave a Reply

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