I do this quite easily using a job scheduler built into my meteor code. I used to use msavin:usercache but that has a ‘wontfix’ performance bug if you define lots of different types of jobs, so now I use my own fork wildhart:meteor-jobs which is more efficient.
I have lots of different types of ‘event’ driven delayed actions. For most of these I delete any previous scheduled jobs of the same type for that user, and then schedule a new job to run after the delay.
E.g. user hasn’t logged in for x days:
// code which runs whenever a user logs in...
Jobs.clear('*', 'sendNotLoggedInRecenlyEmail', userId);
Jobs.run('sendNotLoggedInRecenlyEmail', userId, {in: {days: notLoggedInReminderDays}});
Another way is to set a flag on the user’s record recording the time when they last logged in. Then schedule a repeating job for every 4 hours which queries the Meteor.users db for users who’s lastLoggedInDate is over x days ago, and sends them all an email. I find that 4 hours is a good compromise between sending the email at a time when the user is likely to be awake (since it will be within 4 hours of a time of day when they last logged in), and minimising load on the server.
Having said that, as long as you put indexes on any fields you’ll be querying then I don’t notice any performance hit. I run all these jobs on the same host as my app and DB and I don’t see any 4 hourly spikes at all.
I use this second method every 4 hours to send emails to users who’s subscription will expire in x days.