In the previous blog, we saw how to access data from a S/4HANA system using SAP Cloud SDK in a multitenant application.

In this blog, we will see how to schedule periodic jobs for each of the subscribing tenants to pull data periodically from the backend system and ensure data isolation for each tenant.

 

SAP Job Scheduling Service

SAP Job Scheduling service allows you to define and manage jobs that run once or on a recurring schedule. Use this runtime-agnostic service to schedule action endpoints in your application or long-running processes using Cloud Foundry tasks. Use REST APIs to schedule jobs, including long-running jobs asynchronously, and create multiple schedule formats for simple and complex recurring schedules. Manage jobs and tasks and manage schedules with a web-based user interface.

Implementation

We have admin-srv where the job scheduler is implemented. This microservice is responsible for Updating the application name to adapt to subscribing customers’ names and logos.

 

Creating a Job :

Admin Service offers API where we can pass the job frequency, it then processes it and defines the job.

const JobSchedulerClient = require('@sap/jobs-client');
const xsenv = require('@sap/xsenv');

const jobSchedulerCreds = xsenv.serviceCredentials({ tag: 'jobscheduler' });
const jwt = require('../utility/jwt');

const createJob = async (req, logger) => {
  try {
    const subdomain = req.authInfo.getSubdomain();
    const domain = `https://${subdomain}.${jobSchedulerCreds.uaa.uaadomain}`;
    const token = await jwt(domain, jobSchedulerCreds);
    const options = {
      baseURL: `${jobSchedulerCreds.url}`,
      token: token.accessToken,
    };
    const scheduler = new JobSchedulerClient.Scheduler(options);
// name field is where we are trying to generate a unique name for the job
    const myJob = {
      name: `${subdomain.split("-")[0] + new Date().getMilliseconds()}`,
      description: "cron job that calls HTTP endpoint",
      action: `${process.env.businessPartnerAPI}/api/v1/new/bp`,
// action: URL to the backend service which should be called periodically
      active: true,
      httpMethod: "GET",
      schedules: [
        {
          cron: `* * * * * */${req.query.time} 0`,
// cron: frequency of job
          description: `this schedule runs every ${req.query.time} minutes to fetch the tenant data and find new businesspartners`,
          active: true,
          startTime: {
            date: `${new Date().toISOString().split('T')[0]} 00:00 +0000`,
            format: "YYYY-MM-DD HH:mm Z",
          },
        },
      ],
    };
    const scJob = { job: myJob };

    return new Promise((resolve, reject) => {
      scheduler.createJob(scJob, (error, body) => {
        if (error) {
          logger.error('Error registering new job %s', error);
          return reject(error);
        }
        return resolve(body);
      });
    });
  } catch (schedulererr) {
    logger.error(schedulererr);
    throw new Error("Error While creating the job");
  }
};

Getting Scheduled Jobs

This method returns a list of scheduled jobs for tenants ensuring data isolation for each of tenant.

const getJob = async (req, logger) => {
  try {
    const subdomain = req.authInfo.getSubdomain();
    const domain = `https://${subdomain}.${jobSchedulerCreds.uaa.uaadomain}`;
    const token = await jwt(domain, jobSchedulerCreds);
    const options = {
      baseURL: `${jobSchedulerCreds.url}`,
      token: token.accessToken,
    };
    const scheduler = new JobSchedulerClient.Scheduler(options);
    const data = {};
    return new Promise((resolve, reject) => {
      scheduler.fetchAllJobs(data, (err, result) => {
        if (err) {
           logger.error('Error retrieving jobs: %s', err);
          return reject(err);
        }
        // Jobs retrieved successfully
        logger.info(result)
        return resolve(result);
      });
    });
    
  } catch (errr) {
    logger.error(errr);
    throw errr;
  }
};

 

Here’s how it looks from the Admin dashboard

Scheduled Jobs from the job scheduler dashboard:

Job%20list

Conclusion:  Using re-use services like SAP Job scheduling service in a multitenant application helps in reducing the total cost of application ownership significantly. It is a powerful concept that makes the implementation easier.

Hope this blog series helped you in understanding how to implement a multitenant extension, and application using Nodejs as a programming language and Various service offering on Business Technology Platform.

Further Read:

Other multitenant applications and Missions:

 

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x