zgwldrc
zgwldrc

Reputation: 21

Node-cron Task Fails to Re-enter cron.schedule: Stuck With Async Function Scheduling

I need to run a node-cron task that invokes an async function, which returns a Moment object as the next scheduled time. However, I found that it cannot enter the cron.schedule method twice, and the code gets stuck. Can you guys help me figure out where the problem is?

THE CODE

import cron from 'node-cron';
import moment, {Moment} from 'moment-timezone';

const doTask = async (): Promise<Moment>=> {
    const currentMo = moment()
    const nextMo = currentMo.add(10, 'seconds')
    console.log('do tasking....')
    console.log(`doTask: next schedule time ${nextMo.format('YYYY-MM-DD HH:mm:ss')}`)
    return nextMo
}

class ScheduleManager {
    private task: cron.ScheduledTask | null = null;

    constructor(private scheduleTime: string) {
        this.scheduleTask(this.scheduleTime);
    }

    private scheduleTask(cronExpress: string) {
        if (this.task) {
            console.log(`stop current task`)
            this.task.stop();
        }
        console.log(`start new task with cronExpress: ${cronExpress}`)
        this.task = cron.schedule(cronExpress, async () => {
            const currentMoment = moment()
            console.log('Scheduled task triggered at:', currentMoment.format('YYYY-MM-DD HH:mm:ss'));
            const nextMoment = await doTask();
            this.rescheduleAtMoment(nextMoment);
        });
    }

    private rescheduleAtMoment(nextMoment: Moment) {
        const currentMoment = moment()
        const delay = nextMoment.diff(currentMoment)
        const duration = moment.duration(delay)
        const nextCronExpress = nextMoment.format('ss mm HH DD MM ddd')
        console.log('next schedule time:', nextMoment.format('YYYY-MM-DD HH:mm:ss'));
        const hours = Math.floor(duration.asHours());
        const minutes = Math.floor(duration.asMinutes()) % 60;
        const seconds = Math.floor(duration.asSeconds()) % 60;
        const formattedCountdown = `${hours}Hours,${minutes}Minutes,${seconds}Seconds`;
        console.log(`next schedule time countdown: ${formattedCountdown}`)
        setTimeout(() => {
            console.log(`setTimeout Invoke`)
            this.scheduleTask(nextCronExpress);
        }, delay);
    }
}

const initialScheduleTime = moment().add(5, 'seconds').format('ss mm HH DD MM ddd')
const scheduleManager = new ScheduleManager(initialScheduleTime);

Expected to happen

ScheduleManager continuously calls its own scheduleTask through the rescheduleAtMoment method to achieve self-driving

what actually happened

When ScheduleManager enters scheduleTask for the second time, the code is stuck at
console.log(`start new task with cronExpress: ${cronExpress}`)

Reproduce

npm install  node-cron moment-timezone
npm install -g ts-node
# save above code in to test.ts file
ts-node test.ts

I hope to create an automatically driven node-cron task that schedules a task to get the next expected scheduling time. Then, using setTimeout, reschedule a new task at the next scheduled time.

Upvotes: 2

Views: 28

Answers (0)

Related Questions