Execute a Cron Job every half an hour following the onCreate event in Firestore

Looking to set up a cron job or scheduler that runs every 30 minutes following an onCreate event in Firestore. The goal is to execute a cloud function that retrieves documents created within the last 30 minutes, validates them against a JSON schema, and stores them in a separate collection. How can I programmatically create this scheduler? Additionally, what fail-safe measures can be implemented, as well as a queuing/tracking system for documents created prior to the execution of the cron job?

Answer №1

Creating a queue system with Firestore is straightforward and tailored perfectly to suit your specific needs. The concept involves adding tasks to a designated queue collection with set due dates for processing at the appropriate time.

Let's illustrate this with an example:

  1. Upon triggering the initial onCreate event in your collection, insert a document containing the following data into a tasks collection:
    duedate: new Date() + 30 minutes
    type: 'yourjob'
    status: 'scheduled'
    data: '...' // <-- input any necessary task-specific data here

  1. Have a worker regularly check for available tasks - for instance, every minute based on your requirements
// Define actions for each task type
const workers: Workers = {
  yourjob: (data) => db.collection('xyz').add({ foo: data }),
}


// The following schedule should be implemented:

export const checkQueue = functions.https.onRequest(async (req, res) => {
  // Consistent timestamp
  const now = admin.firestore.Timestamp.now();
  // Identify overdue tasks
  const query = db.collection('tasks').where('duedate', '<=', new Date()).where('status', '==', 'scheduled');
  const tasks = await query.get();
  // Execute tasks and update their status
  tasks.forEach(snapshot => {
    const { type, data } = snapshot.data();
    console.info('Executing job for task ' + JSON.stringify(type) + ' with data ' + JSON.stringify(data));
    const job = workers[type](data)
      // Update task doc with completion status or error
      .then(() => snapshot.ref.update({ status: 'complete' }))
      .catch((err) => {
        console.error('Error when executing worker', err);
        return snapshot.ref.update({ status: 'error' });
      });

    jobs.push(job);
  });
  return Promise.all(jobs).then(() => {
    res.send('ok');
    return true;
  }).catch((onError) => {
    console.error('Error', onError);
  });
});

You have various options for triggering the queue checks for pending tasks:

  • Utilize an HTTP callable function as shown above. This entails making periodic HTTP calls to the function to execute and review pending tasks. You can initiate these calls from your own server or use services like cron-job.org. Keep in mind that the HTTP callable function may be publicly accessible, but if your checking code is idempotent, security concerns should not arise.
  • Opt for the internal Firebase cron option which leverages Cloud Scheduler internally. This allows for direct scheduling of queue checks:
    export scheduledFunctionCrontab =
    functions.pubsub.schedule('* * * * *').onRun((context) => {
        console.log('This will be run every minute!');
        // Include code from checkQueue here from above
    });

Implementing such a queue system enhances the resilience of your application - in case of disruptions, tasks are not lost as they persist until processed by a dedicated worker. However, the successful recovery of tasks relies on the efficiency of your implementation.

Answer №2

If you want to initiate a cloud function when a Firestore document is created, you can set up a process that schedules a Cloud Task 30 minutes after the event. This approach ensures there is a queuing system in place along with retry mechanisms for better reliability.

Answer №3

One simple solution is to include a created field with a timestamp, and then set up a scheduled function that runs at regular intervals (e.g., once per minute) to execute specific code for all records where the

created >= NOW - 31 mins AND created <= NOW - 30 mins
(pseudo code). For most cases, this method should suffice unless you have very precise time requirements.

If this approach doesn't meet your requirements, another option is to utilize Cloud Tasks from Google Cloud. More information on how to do this can be found in this informative article.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The Express application is unable to locate the node_modules directory in order to load scripts

Being relatively new to the behavior of webservers, I have a series of questions that I am hoping someone can assist me with. It would also be greatly appreciated if anyone could provide me with an article or documentation on the topics I'm about to d ...

Unable to access the 'create' property from an undefined source

Currently, I am immersed in a tutorial that delves into the creation of an app using Express, Nodejs, Sequelize, and Postgres. Everything seemed to be going smoothly until I encountered a roadblock - my GET route is functioning perfectly fine, but the POST ...

Retrieve information stored in cookies beyond the component's scope

I've developed a Next.js application with Strapi serving as both the CMS and authentication server. After successfully obtaining a JWT from the authentication endpoint, I have stored it in a cookie. To access secure content from Strapi, I must include ...

Best practices for effectively managing errors within JSON web tokens

I am a novice attempting to manage JWT verification. Within the function below, my goal is for the system to generate a new access token based on the refresh token if the user's access token has expired. import { asyncHandler } from "../utils/asy ...

Sorry, the server cannot be reached at the moment. Please try again later

Recently delving into Node.js and just getting started on using MongoDB. Currently establishing a connection with my MongoDB Cluster that I have set up. const dbURI = 'mongodb+srv://testuser:<a href="/cdn-cgi/l/email-protection" class="__cf_email_ ...

Strategies for resolving the issue of undefined req.body.password in express.js

Hello everyone, I am currently in the process of building an API using EXPRESS.JS and MongoDB. While testing with postman, I encountered an issue where the req.body.password field is undefined when attempting to parse it using postman. Strangely enough, I ...

"Embracing Progressive Enhancement through Node/Express routing and the innovative HIJAX Pattern. Exciting

There may be mixed reactions to this question, but I am curious about the compatibility of using progressive enhancement, specifically the HIJAX pattern (AJAX applied with P.E.), alongside Node routing middleware like Express. Is it feasible to incorporate ...

running a Node JS script using PHP

After executing the command node auth.js in my cmd tool, I encountered an issue where I couldn't retrieve the output. In an attempt to get the JavaScript output in a PHP file, I experimented with the following codes only to receive an empty result: & ...

Flowing Waterways and Transmission Control Protocol

I have a unique piece of code that I recently discovered. After running it, I can connect to it using a Telnet client. const network = require('networking'); //creating the server const server = network.createServer(function (connection) { ...

I'm encountering an issue where the database table in Postgres is not updating correctly while working with Node

Currently, I am working on a CRUD application where I can successfully read and delete data from the database table. However, I have encountered an issue when trying to update specific data for a particular route. Every time I attempt to update the data in ...

Oops! The mighty gulp-clean frowns upon attempts to eradicate files outside its domain

Whenever I execute the command: gulp clean I encounter an error even though I tried using: gulp clean --force but it didn't work. Could someone please clarify what might be causing this issue or what mistake I am making? Your help would be greatly ...

Extract website addresses from a text and store them in an array

I am currently attempting to extract URLs from a string and store them in an array. I have implemented a node module to assist with this task. const getUrls = require("get-urls") url = getUrls(message.content) However, the current implementation fails to ...

Pass on Redis Pub/Sub messages to a designated client in socket.io through an Express server

Currently, in my express server setup, I am utilizing socket.io and Redis pubsub. The process involves the server subscribing to a Redis message channel and then forwarding any incoming Redis messages to a specific WebSocket client whenever a new message i ...

GULP showing an error message "ACCESS DENIED"

Exploring the fascinating realm of Gulp for the first time has been quite an adventure. I have managed to create a gulpfile that effectively handles tasks like reading, writing, and compiling sass/css/js/html files. However, when I try to access the site o ...

Troubles encountered while attempting to properly mock a module in Jest

I've been experimenting with mocking a module, specifically S3 from aws-sdk. The approach that seemed to work for me was as follows: jest.mock('aws-sdk', () => { return { S3: () => ({ putObject: jest.fn() }) }; }); ...

Rendering on the server with a focus on the header

Can server side rendering be limited to only <head></head> data? I am exploring options similar to next.js: export async function getServerSideProps(context) { return { props: {}, // will be passed to the page component as props } } Ba ...

Granting permission to the user

I am facing an issue with authorizing the admin user. Although the backend code is functioning properly, I am encountering difficulties in requesting the admin route and authenticating the logged-in user. Initial attempts involved storing the isAdmin value ...

Navigating through async functions in an Express.js router

Encountered a lint error indicating that Promises cannot be returned in places where a void is expected. Both functions [validateJWT, getUser] are async functions. Any suggestions on how to resolve this issue without compromising the linter guidelines by u ...

Steps for integrating a Facebook Messenger chatbot with a MongoDB database in order to submit requests and retrieve responses through conversations with the bot

I am currently working on integrating my Facebook Messenger chatbot with a MongoDB database. The chatbot I have created is a simple questionnaire chatbot that takes text inputs and displays buttons with options. When a user clicks on a button, it should ...

How can I retrieve the GET parameters following the "?" in an Express application?

When dealing with queries like this, I am familiar with how to obtain the parameters: app.get('/sample/:id', routes.sample); In such scenarios, I can easily retrieve the parameter using req.params.id (for example, 2 in /sample/2). However, whe ...