Store and execute future actions.
Use the scheduler to do things like send a private message at a specified time, track upvotes, or schedule time-outs for user actions.
Create a job definition using Devvit.addSchedulerJob method.
Devvit.addSchedulerJob({
name: 'thing-todo', // you can use an arbitrary name here
onRun: async (event, context) => {
// do stuff when the job is executed
},
});Use the context.scheduler.runJob() method to schedule the job you created. You can schedule the job to run once at at a particular time in the future or schedule it to be called repeatedly at a specific time.
- To schedule the job to run once, use the
runAtparameter:
Devvit.addMenuItem({
label: 'Remind me about this post',
location: 'post',
onPress: async (event, context) => {
const jobId = await context.scheduler.runJob({
name: 'thing-todo', // the name of the job that we specified in addSchedulerJob() above
runAt: new Date('2099-01-01'),
});
},
});Optionally, you can save the jobId in Redis storage to be able to cancel the scheduled action in the future.
await context.redis.set('thing-todo:jobId', jobId);- To schedule a recurring action, use a
cronparameter:
:::note
scheduler.runJob() uses the same format that is used in UNIX cron, a command-line utility is a job scheduler on Unix-like operating systems https://en.wikipedia.org/wiki/Cron
# * * * * *
# | | | | |
# | | | | day of the week (0–6) Sunday to Saturday; 7 is also Sunday on some systems
# | | | month (1–12)
# | | day of the month (1–31)
# | hour (0–23)
# minute (0–59)
:::
Devvit.addMenuItem({
label: 'Run every day',
location: 'post',
onPress: async (event, context) => {
const jobId = await context.scheduler.runJob({
name: 'thing-todo',
cron: '0 12 * * *',
});
},
});:::note We recommend using Cronitor to build out strings. :::
Use the job ID to cancel a scheduled action and remove it from your app.
Devvit.addMenuItem({
label: 'clear',
location: 'post',
forUserType: 'moderator',
onPress: async (_event, context) => {
const jobId = (await context.redis.get('jobId')) || '0';
await context.scheduler.cancelJob(jobId);
},
});
export default Devvit;You can schedule an action to run once at a specific time, like sending a private message in the Remind Me tutorial.
import { Devvit } from '@devvit/public-api';
const REMIND_ME_ACTION_NAME = 'remindme';
Devvit.addSchedulerJob({
name: REMIND_ME_ACTION_NAME,
onRun: async (event, context) => {
const { userId, postId, fromWhen } = event.data!;
const user = await context.reddit.getUserById(userId);
const post = await context.reddit.getPostById(postId);
// Send a private message to the user
await context.reddit.sendPrivateMessage({
to: user.username,
subject: 'RemindMe',
text: `Beep boop! You asked me to remind you about [${post.title}](${post.permalink}) at ${fromWhen}!`,
});
},
});
Devvit.addMenuItem({
label: 'Remind me about this post',
location: 'post',
onPress: async (event, context) => {
// Code below could also be run from another capability, like an event trigger or another scheduled job
const today = new Date();
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);
await context.scheduler.runJob({
name: REMIND_ME_ACTION_NAME,
data: {
userId: context.userId!,
postId: `t3_${context.postId}`,
},
runAt: tomorrow,
});
},
});
export default Devvit;You can schedule an action that repeats at a specific time. This sample code creates a recurring action to post a new daily thread every day at 12:00 UTC. In this example, the recurring action is initiated when the app is installed, but you can also schedule a recurring action from a menu action instead.
import { Devvit } from '@devvit/public-api';
Devvit.addSchedulerJob({
name: 'daily_thread',
onRun: async (_event, context) => {
console.log('daily_thread handler called');
const subreddit = await context.reddit.getCurrentSubreddit();
const resp = await context.reddit.submitPost({
subredditName: subreddit.name,
title: 'Daily Thread',
text: 'This is a daily thread, comment here!',
});
console.log('posted resp', JSON.stringify(resp));
},
});
Devvit.addTrigger({
event: 'AppInstall',
onEvent: async (_event, context) => {
try {
const jobId = await context.scheduler.runJob({
cron: '0 12 * * *',
name: 'daily_thread',
data: {},
});
await context.redis.set('jobId', jobId);
} catch (e) {
console.log('error was not able to schedule:', e);
throw e;
}
},
});
export default Devvit;:::note We recommend using Cronitor to build out strings. :::
:::note This feature is experimental, which means the design is not final but it's still available for you to use. :::
Scheduled jobs currently perform one scheduled run per minute. To go faster, you can now run jobs every second by adding seconds granularity to your cron expression.
await scheduler.runJob({
name: 'run_every_30_seconds',
cron: '*/30 * * * * *',
});How frequent a scheduled job runs will depend on how long the job takes to complete and how many jobs are running in parallel. This means a job may take a bit longer than scheduled, but the overall resolution should be better than a minute.
Limits are per installation of an app
-
An installation can have up to 10 live recurring actions.
-
There are two rate limits enforced by the
runJob()method when actions are created:- Creation rate: up to 60 calls to
runJob()per minute - Delivery rate: up to 60 deliveries per minute
- Creation rate: up to 60 calls to