const { Types } = require('mongoose'); const { Service } = require('feathers-mongoose'); const _ = require('lodash'); const cron = require('cron'); const Bluebird = require('bluebird'); const Model = require('./event.model.js'); const handleAttendClassJob = require('../../handlers'); const CronJob = cron.CronJob; const handleTestJob = () => new Promise(res => setTimeout(res, 10000)); class Events extends Service { async setup(app, path) { this.jobs = []; await this.rescheduleMissedEvents(); const job = new CronJob('*/10 * * * * *', () => this.updateJobs()); job.start(); } startAllJobs() { this.jobs.forEach(job => job.start()); } stopAllJobs() { this.jobs.forEach(job => job.stop()); } async rescheduleMissedEvents() { const missedEvents = await this.Model.findMissedEvents(); return Bluebird.map(missedEvents, event => event.save()); } async updateJobs() { // Reschedule missed events before we stop jobs to avoid // accidentally stopping the job that has not triggered yet // (if event schedule resonates with updateJobs schedule) await this.rescheduleMissedEvents(); this.stopAllJobs(); const events = await this.Model.findNextEvents(); if (!events.length) this.log('No upcoming events.'); this.jobs = events.map(event => new CronJob( event.schedule, () => this.run(event._id) )); this.startAllJobs(); } log(message) { const dateOpts = { timeStyle: 'medium', dateStyle: 'short' }; const timestamp = new Date().toLocaleString('en', dateOpts); return console.log(`[${timestamp}] ${message}`); } async run(id) { const event = await this.Model.findById(id); event.lastRunAt = new Date(); event.setStatus('running') try { this.log(`Event ${event.name} started`) await handleTestJob(event); this.log(`Event ${event.name} ended`) } catch (error) { event.setStatus('failed') } if (event.status === 'running') { event.setStatus('complete') } } } module.exports = app => { app.use('/events', new Events({ Model })); };