LogoRobo.js

Persistence

Save cron jobs across restarts and manage them dynamically.

By default, cron jobs only live in memory. When your Robo restarts, they're gone. Persistence lets file-based jobs survive restarts and be retrieved or removed at any time.

Saving jobs

Call .save() on a file-based job to persist it. The plugin stores the cron expression and file path in Flashcore so the job can be restored on the next startup.

import { Cron } from '@robojs/cron'

const job = Cron('0 0 * * *', 'cron/daily-report.js')
const jobId = await job.save()
import { Cron } from '@robojs/cron'

const job = Cron('0 0 * * *', 'cron/daily-report.js')
const jobId = await job.save()

The save() method returns the job ID — a UUID by default. Pass a custom ID to make retrieval easier and prevent duplicates.

const jobId = await job.save('daily-report')
const jobId = await job.save('daily-report')

Only file-based jobs can be persisted. Function-based jobs (inline callbacks) are stored in memory only and will not survive restarts, even if you call .save() on them.

Retrieving jobs

Use Cron.get() to retrieve a running job by its ID.

const job = Cron.get('daily-report')
if (job) {
	console.log('Next run:', job.nextRun())
}
const job = Cron.get('daily-report')
if (job) {
	console.log('Next run:', job.nextRun())
}

Cron.get() returns the CronJob instance or null if not found. This is a synchronous call that reads from the in-memory state — it does not query Flashcore directly.

After a restart, jobs are available via Cron.get() only after the plugin's startup handler has finished restoring them from Flashcore.

Removing jobs

Use Cron.remove() to delete a job's persistence and clear it from memory.

await Cron.remove('daily-report')
await Cron.remove('daily-report')

This removes the job from Flashcore and the in-memory state. However, it does not stop a running job. For a complete cleanup, stop the job first.

const job = Cron.get('daily-report')
job?.stop()
await Cron.remove('daily-report')
const job = Cron.get('daily-report')
job?.stop()
await Cron.remove('daily-report')

Startup restoration

When your Robo starts, the plugin's start hook automatically restores all persisted jobs:

Read the job index

The plugin reads the list of saved job IDs from Flashcore.

Restore each job

For each ID, it loads the stored cron expression and file path, then recreates the job with Cron(expression, path).

Handle failures

If a job's data is missing or the job fails to create, the plugin logs a warning and removes the stale entry. Individual failures don't block other jobs from restoring.

This process is automatic. You don't need to write any restoration code yourself.

Dynamic job management

Persistence is especially useful for jobs created at runtime — for example, from a slash command.

schedule.tsCreates cron jobs
cancel.tsCancels cron jobs
reminder.jsJob handler
src/commands/schedule.ts
import { Cron, Patterns } from '@robojs/cron'
import type { CommandInteraction } from 'discord.js'

export default async (interaction: CommandInteraction) => {
	const userId = interaction.user.id
	const jobId = `reminder-${userId}`

	// Create and persist the job
	const job = Cron(Patterns.everyDayAt('09:00'), 'cron/reminder.js')
	await job.save(jobId)

	return `Reminder set. Job ID: ${jobId}`
}
src/commands/schedule.js
import { Cron, Patterns } from '@robojs/cron'

export default async (interaction) => {
	const userId = interaction.user.id
	const jobId = `reminder-${userId}`

	// Create and persist the job
	const job = Cron(Patterns.everyDayAt('09:00'), 'cron/reminder.js')
	await job.save(jobId)

	return `Reminder set. Job ID: ${jobId}`
}
src/commands/cancel.ts
import { Cron } from '@robojs/cron'
import type { CommandInteraction } from 'discord.js'

export default async (interaction: CommandInteraction) => {
	const userId = interaction.user.id
	const jobId = `reminder-${userId}`

	const job = Cron.get(jobId)
	if (!job) {
		return 'No active reminder found.'
	}

	job.stop()
	await Cron.remove(jobId)
	return 'Reminder cancelled.'
}
src/commands/cancel.js
import { Cron } from '@robojs/cron'

export default async (interaction) => {
	const userId = interaction.user.id
	const jobId = `reminder-${userId}`

	const job = Cron.get(jobId)
	if (!job) {
		return 'No active reminder found.'
	}

	job.stop()
	await Cron.remove(jobId)
	return 'Reminder cancelled.'
}

Function-based vs file-based

FeatureFunction-basedFile-based
Inline callbackYesNo
PersistableNoYes
Survives restartsNoYes (when saved)
Retrievable via Cron.get()Only if .save() was called in current processYes, after restoration

Function-based jobs are best for tasks that should only run while the process is active. File-based jobs are the way to go for anything that needs to survive restarts.

Gotchas

  • stop() does not remove persistence. A stopped job that was saved will be restored on the next restart. Always call Cron.remove(id) if you want to fully remove it.
  • Cron.get() is runtime-only. It reads from in-memory state, not Flashcore. After a restart, it only works after the startup restoration completes.
  • Custom ID collisions overwrite. Calling .save('my-id') on two different jobs with the same ID will overwrite the first in storage.
  • Calling .save() with different IDs on the same job changes the job's internal ID but does not clean up the old entry. Use a consistent ID per job.

Next Steps

On this page