226 lines
5.3 KiB
JavaScript
226 lines
5.3 KiB
JavaScript
const cron = require('node-cron');
|
|
const { User } = require('../../models');
|
|
const TaskSummaryService = require('./taskSummaryService');
|
|
const { setConfig, getConfig } = require('../../config/config');
|
|
const config = getConfig();
|
|
|
|
const createSchedulerState = () => ({
|
|
jobs: new Map(),
|
|
isInitialized: false,
|
|
});
|
|
|
|
let schedulerState = createSchedulerState();
|
|
|
|
const shouldDisableScheduler = () =>
|
|
config.environment === 'test' || config.disableScheduler;
|
|
|
|
const createJobConfig = () => ({
|
|
scheduled: false,
|
|
timezone: 'UTC',
|
|
});
|
|
|
|
const getCronExpression = (frequency) => {
|
|
const expressions = {
|
|
daily: '0 7 * * *',
|
|
weekdays: '0 7 * * 1-5',
|
|
weekly: '0 7 * * 1',
|
|
'1h': '0 * * * *',
|
|
'2h': '0 */2 * * *',
|
|
'4h': '0 */4 * * *',
|
|
'8h': '0 */8 * * *',
|
|
'12h': '0 */12 * * *',
|
|
cleanup_tokens: '0 2 * * *',
|
|
deferred_tasks: '*/5 * * * *',
|
|
due_tasks: '*/15 * * * *',
|
|
due_projects: '*/15 * * * *',
|
|
};
|
|
return expressions[frequency];
|
|
};
|
|
|
|
const createJobHandler = (frequency) => async () => {
|
|
if (frequency === 'cleanup_tokens') {
|
|
await cleanupExpiredTokens();
|
|
} else if (frequency === 'deferred_tasks') {
|
|
await processDeferredTasks();
|
|
} else if (frequency === 'due_tasks') {
|
|
await processDueTasks();
|
|
} else if (frequency === 'due_projects') {
|
|
await processDueProjects();
|
|
} else {
|
|
await processSummariesForFrequency(frequency);
|
|
}
|
|
};
|
|
|
|
const createJobEntries = () => {
|
|
const frequencies = [
|
|
'daily',
|
|
'weekdays',
|
|
'weekly',
|
|
'1h',
|
|
'2h',
|
|
'4h',
|
|
'8h',
|
|
'12h',
|
|
'cleanup_tokens',
|
|
'deferred_tasks',
|
|
'due_tasks',
|
|
'due_projects',
|
|
];
|
|
|
|
return frequencies.map((frequency) => {
|
|
const cronExpression = getCronExpression(frequency);
|
|
const jobHandler = createJobHandler(frequency);
|
|
const jobConfig = createJobConfig();
|
|
const job = cron.schedule(cronExpression, jobHandler, jobConfig);
|
|
|
|
return [frequency, job];
|
|
});
|
|
};
|
|
|
|
const startJobs = (jobs) => {
|
|
jobs.forEach((job, frequency) => {
|
|
job.start();
|
|
});
|
|
};
|
|
|
|
const stopJobs = (jobs) => {
|
|
jobs.forEach((job, frequency) => {
|
|
job.stop();
|
|
});
|
|
};
|
|
|
|
const fetchUsersForFrequency = async (frequency) => {
|
|
return await User.findAll({
|
|
where: {
|
|
telegram_bot_token: { [require('sequelize').Op.ne]: null },
|
|
telegram_chat_id: { [require('sequelize').Op.ne]: null },
|
|
task_summary_enabled: true,
|
|
task_summary_frequency: frequency,
|
|
},
|
|
});
|
|
};
|
|
|
|
const sendSummaryToUser = async (userId, frequency) => {
|
|
try {
|
|
const success = await TaskSummaryService.sendSummaryToUser(userId);
|
|
return success;
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const processSummariesForFrequency = async (frequency) => {
|
|
try {
|
|
const users = await fetchUsersForFrequency(frequency);
|
|
|
|
const results = await Promise.allSettled(
|
|
users.map((user) => sendSummaryToUser(user.id, frequency))
|
|
);
|
|
|
|
return results;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
const cleanupExpiredTokens = async () => {
|
|
try {
|
|
const {
|
|
cleanupExpiredTokens: cleanup,
|
|
} = require('./registrationService');
|
|
const count = await cleanup();
|
|
return count;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
const processDeferredTasks = async () => {
|
|
try {
|
|
const { checkDeferredTasks } = require('./deferredTaskService');
|
|
const result = await checkDeferredTasks();
|
|
return result;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
const processDueTasks = async () => {
|
|
try {
|
|
const { checkDueTasks } = require('./dueTaskService');
|
|
const result = await checkDueTasks();
|
|
return result;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
const processDueProjects = async () => {
|
|
try {
|
|
const { checkDueProjects } = require('../projects/dueProjectService');
|
|
const result = await checkDueProjects();
|
|
return result;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
const initialize = async () => {
|
|
if (schedulerState.isInitialized) {
|
|
return schedulerState;
|
|
}
|
|
|
|
if (shouldDisableScheduler()) {
|
|
return schedulerState;
|
|
}
|
|
|
|
const jobEntries = createJobEntries();
|
|
const jobs = new Map(jobEntries);
|
|
|
|
startJobs(jobs);
|
|
|
|
schedulerState = {
|
|
jobs,
|
|
isInitialized: true,
|
|
};
|
|
|
|
return schedulerState;
|
|
};
|
|
|
|
const stop = async () => {
|
|
if (!schedulerState.isInitialized) {
|
|
return schedulerState;
|
|
}
|
|
|
|
stopJobs(schedulerState.jobs);
|
|
|
|
schedulerState = createSchedulerState();
|
|
|
|
return schedulerState;
|
|
};
|
|
|
|
const restart = async () => {
|
|
await stop();
|
|
return await initialize();
|
|
};
|
|
|
|
const getStatus = () => ({
|
|
initialized: schedulerState.isInitialized,
|
|
jobCount: schedulerState.jobs.size,
|
|
jobs: Array.from(schedulerState.jobs.keys()),
|
|
});
|
|
|
|
module.exports = {
|
|
initialize,
|
|
stop,
|
|
restart,
|
|
getStatus,
|
|
processSummariesForFrequency,
|
|
cleanupExpiredTokens,
|
|
processDeferredTasks,
|
|
processDueTasks,
|
|
processDueProjects,
|
|
_createSchedulerState: createSchedulerState,
|
|
_shouldDisableScheduler: shouldDisableScheduler,
|
|
_getCronExpression: getCronExpression,
|
|
};
|