Most Ideal Way to Run a Scheduled Job with Angular-Meteor - node.js

I'm writing an appointment scheduling app with angular-meteor. One of the requirements is that a text notification be sent out to the customer who made the appointment. The customer provides a cell number. But basically, all I want to do is send out an email X many minutes before the appointment time. Running off the angular-meteor stack, what might be the best way to do this? All of the appointment information is saved to a mongo db.

You might be interested in Meteor job-collection package (not specific to angular-meteor):
A persistent and reactive job queue for Meteor, supporting distributed workers that can run anywhere.
job-collection is a powerful and easy to use job manager designed and built for Meteor.js.
It solves the following problems (and more):
Schedule jobs to run (and repeat) in the future, persisting across server restarts
[…]
In particular job.after(someTimeBeforeAppointment)
// Server
var myJobs = JobCollection('myJobQueue');
// Start the myJobs queue running
myJobs.startJobServer();
// Create a Job (e.g. in a Meteor method)
var job = new Job(myJobs, 'jobType', jobData);
// Specify when it can run and save it.
job.after(someTimeBeforeAppointment).save();
// Server (or could be a different server!)
// How jobs should be processed.
myJobs.processJobs('jobType', function (job, done) {
var jobData = job.data;
// Do something… could be asynchronous.
job.done(); // or job.fail();
// Call done when work on this job has finished.
done();
});
The pollInterval can be specified in processJobs options. Default is every 5 seconds.

Write a node script that sends an email to every customer who has an appointment between X minutes and X+10 minutes from the time of running. Once the email is sent, set a boolean flag on the appointment in mongo so it doesn't get sent twice.
Run a cron that triggers it every 5 minutes.
The overlap should make sure that nothing slips though the cracks, and the flag will prevent multiples from being sent.

Related

Creating atomic function in nodejs

The title isn't accurate because based on what I have found in my research there doesn't seem to be a way to make a function atomic in nodejs, but I will lay out my problem to see if you people can come up with something that I have not been able to think about.
I am trying to setup a scheduler where I can set my appointment time slots say 1 hr long each and when someone makes an appointment I want to make sure that the time slot is not taken before scheduling it.
So for example I decide that I will be working from 9 am to 2 pm with a time slot of one hour. Then my schedule would be 9-10, 10-11, 11-12, 12-1, 1-2.
An appointment will come in with a start time of 11 and end time of 12. I need to make sure that slot isn't already taken.
I am using mongodb with nodejs and restify.
I understand that in my appointments collection I can set an index on a combination of values like start time and end time, as discussed here Creating Multifield Indexes in Mongoose / MongoDB.
But if I decide to change my time slot from 1 hour to say 1.5 hours then I will have scheduling conflicts as the start time and end time of entries in the database will not match up with the new interval
Currently I have a function which checks to make sure that the new appointment will not conflict but I am not sure if it will work out well when I have multiple requests coming in. This is a nodejs and restify app so basically an api with a mongodb that it talks to, to handle appointments.
I am running it with multiple workers, so I am worried that at a certain point two requests will come in at the same time, handled by two different workers for the same time slot. When my conflict checking function executes it will return saying that the slot is open for both of them since no appointment has been made yet and then there will be a scheduling conflict.
Any ideas on how to combat this, or is there something in the way javascript executes so that I shouldn't have to worry about it this? All input will be appreciated
Thanks!
I ended up using https://github.com/Automattic/kue, to queue my requests and added another endpoint where you can check the status of your request. So when you want to make an appointment your request ends up in the job queue, and you can then periodically check the status of your request. This way only one appointment request gets processed at a time so no concurrency issues.

setTimeouts not always working on node.js discord bot

I created a discord bot using Node.js and the discord.js-commando framework.
One of the features is to create writing sprints, which essentially is a timer, so you could say: I want to write for 20 minutes, starting in 5 minutes. The bot would then wait 5 minutes and start the sprint, then after 20 minutes it notifies the users doing it that it's ended and waits for wordcounts to come in, then posts the results.
This was working fine when the bot was only on one server, but it's been added to several more recently (78 according to the !stats command, though I don't know how many are actively using it), and since then, it's been very erratic.
Sometimes the sprint never starts, sometimes it never ends, sometimes it ends and then after you post your wordcounts, it never posts the final results.
This is my first ever dabbling with Node.js, so I don't know if I'm doing something wrong. I am doing all of the timers with the setTimeout function.
Here is the command file: link to GitHub
As an example, this is the timeout that is set after a user submits their wordcount, if everyone has now submitted their wordcount, so we can display the results:
msg.say('The word counts are in. Results coming up shortly...');
this.finished = 1;
// Clear original timeout
this.clear();
// Set new one
this.messageTimeout = setTimeout(function() {
obj.finish(msg);
}, 10000);
Where clear is:
clear() {
clearTimeout(this.messageTimeout);
}
Is there something inherently wrong with doing it this way? I know very little about Node.js... Should I perhaps look at doing a cron every minute instead to process sprints? Or could this be a server issue? I am running it on a free EC2 AWS server, but the reports all look okay, no resources are being used at abnormally high levels.
Thanks.

How to frequent compare 2 dates for a huge set of objects (as cronjob) - nodejs

My system has tasks that has a deadline (as date stored in the database) differ from task to another, I want to check frequently for these tasks if they exceed their deadline (basically with the current date I guess), and if so send a notification or execute a function
How can I make this function to be executed as cronjob or as it is without the help of cronjob.
I want to do this without making heavy load on the server
I'm using Express and sequelize as ORM
I did see node-cron as scheduler but i don't have the idea to implement something like this
I would appreciate any help :)
You can use later package for this tasl like that:
https://github.com/bunkat/later
var later = require('later');
later.date.UTC();
const DEDLINE_SCHEDULE = later.parse.text('every 1 min');
later.setInterval(createNotificationJob(), DEDLINE_SCHEDULE);
function createNotificationJob() {
// check are tasks exceed their dedline
}
and then every 1 minute you can check that if tasks exceed their deadline and send notification.

Scheduling Tasks in Node.js Using Timers instead of Scheduled Cron Jobs

This is my objective:
5 minutes after the last document update, I want to execute a one-time task
So this is what the flow of actions will look like:
User updates document - timer is started and counts down from 5 minutes
If user updates the same document again and the previous timer (identified by the document._id) is running still, reset that timer back to 5 minutes and repeat countdown
When timer has elapsed - the one time task is executed
I have not done something like this before and I am at a loss at where to begin.
I can hook into document changes easily using methods available in Mongoose (i.e. on save, do func to setup or reset timer)
However, I cannot figure out the way to:
create a timer that waits 5 minutes - then executes a task
making the timer accessible so that I can reset the timer
making the timer accessible so I can add extra variables which will be used in the funtion when timer has elapsed
I've investigated Cron jobs but they seem to tasks that schedule at the same time everyday.
I need a timer that delays a task, but also the ability to reset that timer, and add extra data to the timer.
Any hints appreciated.
This is the solution I managed to complete up with.
First of all, it's worth noting that my original assumptions are correct:
Cron jobs are great for repetitive, tasks that are scheduled at the same time everyday. However, for tasks that are created on the fly, and have a countdown element, then cron jobs isn't the right tool.
However, enter node-schedule (https://www.npmjs.com/package/node-schedule)
Node Schedule is a flexible cron-like and not-cron-like job scheduler for Node.js. It allows you to schedule jobs (arbitrary functions) for execution at specific dates, with optional recurrence rules. It only uses a single timer at any given time (rather than reevaluating upcoming jobs every second/minute).
The use of timers is really what these, on-the-fly tasks need.
So my solution looks like this:
var schedule = require('node-schedule'),
email_scheduler = {};
email_scheduler["H1e5nE2GW"] = schedule.scheduleJob(Date.now() + 10000, function(){
console.log('its been a total of 10 seconds since initalization / reset.');
});
var second_attempt = schedule.scheduleJob(Date.now() + 5000, function(){
console.log("5 seconds elapsed from start, time to reset original scheduled job");
email_scheduler["H1e5nE2GW"].cancel();
email_scheduler["H1e5nE2GW"] = schedule.scheduleJob(Date.now() + 10000, function(){
console.log('its been a total of 10 since last one seconds.');
});
schedule.scheduleJob(Date.now() + 5000, function(){
console.log("it's been another 5 seconds since reset");
});
});
My thinking (though not yet tested) is that I can create a singleton-like instance for the email_scheduler object by creating a node module. Like such:
// node_modules/email-scheduler/index.js
module.exports = {};
This way, I can access the scheduleJobs and reset the timers in every file of the node application.
You can use events for that. call a event with some parameter and before your task add sleep and exec your task. But add sleep or settimeout is not a good idea in nodejs.
I had the same puzzle but I ended settling on the javascript native functions.
function intervalFunc() {
//inside this function you can request to get the date and time then decide what to do and how to do it
autogens.serverAutoGenerate();//my function to autogenerate bills
}
setInterval(intervalFunc, 1000);//repeat task after one seconds
Adding the code at the index file or entry file of your node js application will make the function repeatedly execute. You can opt to change the frequency depending on your needs. If you wanted to run the cronjob three times a day, get the number of seconds in 24 hours then divide by 3. If you wanted to run the job on a specific hour, by using the new Date(), you can check to determine if it is the right hour to execute your event or not.

firebase-queue: Multiple workers not running correctly?

I'm pretty new to Node.js, though I've been writing javascript for years. I'm more than open to any node advice for best-practices that I'm not following, or other rethinks. That said:
I'm building a system in which a user creates a reservation, and simultaneously submits a task for my firebase-queue to pick up. This queue has multiple specs associated with it. In turn, it's supposed to:
check availability, and in response confirm/throw an alert on the reservation and update the firebase data accordingly.
Update the users reservations, which is an index of reservation object keys, and removing any redundant ones.
Use node-schedule to create dated functions to send notifications about the pending expiration of their reservation.
However, when I run my script, only one of the firebase-queues that I instantiate runs. I can look in the dashboard and see that the progress is at 100, the _state is the new finished_state (which is the next spec's start_state), but that next queue won't pick up the task and process it.
If I quit my script and rerun it, that next queue will work fine. And then the queue after that won't work, until I repeat the act of quitting and rerunning the script. I can continue this until the entire task sequence completes, so I don't think the specs or the code being executed itself are blocking. I don't see any error states spring up, anyway.
From the documentation it looks like I should be able to write the script this way, with multiple calls to 'new Queue(queueRef, options, function(data, progress, resolve, reject)...' and they'll just run each task as I set them in their options (all of which are basically:
var options = {
'specId': 'process_reservation',
'numWorkers': 5,
'sanitize': true,
'suppressStack': false
};
but, nope. I guess I can spawn child-processes for each of the queue instances, but I'm not sure if that's an extreme reaction to the issues I'm seeing, and I'm not sure if it would complicate the node structure in terms of shared module exports. Also, I'm not sure if it'll start eating into my concurrent connection count.
Thanks!

Resources