Have your say in Community Polls: What was/is your greatest motivation to start your own business?
Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Cron job in Shopify

Cron job in Shopify

mohit12
Shopify Partner
8 0 2

Hello Folks,
I have query , I am making an App in remix and Graphql  .Can anyone tell how we can implement Cron Job in Remix (react library )and Graphql  in shopify app

Replies 5 (5)

Liam
Community Manager
3108 344 894

Hi Mohit12,

 

You can implement a Cron Job in your app, but it's not something that is directly related to Remix or GraphQL. It more so depends on the environment where your app is running. However, if you're looking to schedule some tasks, you could do it server-side, where your app is running. Here's a general way of how you can set up a cron job in Node.js environment:

  1. Install the node-cron package: npm install --save node-cron

  2. Import and use it in your Node.js script:

const cron = require('node-cron');

cron.schedule('* * * * *', () => {
   console.log('Running a task every minute');
});

In the context of Shopify, you might want to run a task that fetches or updates some data via the Shopify API. In this case, you can use GraphQL queries/mutations within these tasks.

For example:

const cron = require('node-cron');
const { request } = require('graphql-request')

cron.schedule('* * * * *', () => {
   const query = `{
     shop {
       name
       primaryDomain {
         url
         host
       }
     }
   }`

   request('https://your-shopify-store.myshopify.com/api/graphql', query)
     .then(data => console.log(data))
     .catch(err => console.log(err))
});

This will fetch the name and primary domain of your shop every minute. Please note that this is a simplified example. In a real-world scenario, you'd need to handle API authentication and error handling as well.

 

Hope this helps,

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Charles_Roberts
Shopify Partner
49 0 17

Hi @Liam 

 

Thanks for this information. 
In relation to Remix, where would we add the:

 

const cron = require('node-cron');

 

Would this go in the Shopify.server.js or entry.server.jsx or perhaps it could be used in the loader method of a route?

 

Or would I set up a separate mini application with a server.js file, that would make an api call, inside the cron.schedule(), to one of my remix application’s routes, where I have some business logic that I wish to schedule. 

I must say I would prefer to keep everything inside my Remix app. 
I cannot see any reason, why I can’t import the  node-cron library to a route and use it inside the loader or action method. Both of these are server side methods. 

Charles_Roberts
Shopify Partner
49 0 17

Plus when node-cron is imported, does this require cron to be available on the host? Or does NodeJs just emulate what cron does? I mean a NodeJs server is running 24/7, so it should have some sort of scheduling capability?

ThorMolly
Shopify Partner
4 0 2

Hey @Charles_Roberts, did you figure out where to place the cronjob? I am not sure either. Thanks!

Charles_Roberts
Shopify Partner
49 0 17

Here is an excerpt from:

 

app/routes/app.cron.($id).jsx

 

 

let job = {};

export async function loader({ request, params }) {
  const { admin, session } = await authenticate.admin(request);
  const { shop } = session;

  if('id' in params){
    const action = params.id;
    createCron(action, shop, process);
  }

  return json({
    ownerKey: '',
    action: '',
    error: ''
  });
}

export async function action({ request, params }) {
  const { admin, session } = await authenticate.admin(request);
  const { shop } = session;

  const formData$ = await request.formData();
  const formData = Object.fromEntries(formData$);

  /** @type {any} */
  const data = {
    ...formData
  };

  const errors = validateCronForm(data);

  if (errors) {
    return json({ errors }, { status: 422 });
  }

  const action = formData.action;

  let cronResponse = {};
  let error = '';

  if(formData.ownerKey === process.env.OWNER_KEY){
    cronResponse = createCron(action, shop, process);
    if('error' in cronResponse){
      // @ts-ignore
      error = 'Task threw an error';
    }
  }
  else{
    error = 'Owner key did not match';
  }

  return json({
    responseData: {
      ownerKey: formData.ownerKey,
      action: formData.action === 'start' ? 'started' : 'stopped',
      error
    },
    errors
  });
}

function createCron(action, shop, process){

  const cron = require('node-cron');

  const cronTime = process.env.ENVIRONMENT === 'prod' ? '30 1 * * * ' : '30 * * * * * ';

  let error = false;

  const tasks = cron.getTasks();

  let deferReadOrdersTaskExists = false;

  for (let [key, value] of tasks.entries()) {
    if(value.options.name === 'deferReadOrders-task'){
      deferReadOrdersTaskExists = true;
      break;
    }
  }

  if(!deferReadOrdersTaskExists){
    job = cron.schedule(cronTime, async function execute() {
      const date = new Date().toLocaleString();
      const days = [14,7,3];
      const res = deferReadOrders(days, shop, process);
    },{
      name: 'deferReadOrders-task',
      scheduled: false
    });
  }

  try{
    action == 'stop' ? job.stop() : job.start();
  }
  catch(error){
    job.stop();
    error = true;
  }

  return json({
    cronTime,
    action,
    error
  });
}