| name | cursor-plugin-convex-rule-scheduler-usage |
| description | Only schedule internal functions, never api functions |
| metadata | {"version":"0.1.0"} |
Scheduler and Action Safety
Always schedule internal functions with ctx.scheduler, ctx.runAfter, ctx.runAt, and ctx.run* methods. Never schedule public api functions.
Why
Scheduled functions bypass authentication and argument validation that public APIs expect to receive from clients.
Pattern
Bad:
import { api } from "./_generated/api";
export const processPayment = action({
handler: async (ctx, args) => {
await ctx.scheduler.runAfter(0, api.users.chargeUser, {
userId: args.userId,
amount: args.amount,
});
},
});
Good:
import { internal } from "./_generated/api";
export const chargeUserInternal = internalMutation({
args: { userId: v.id("users"), amount: v.number() },
handler: async (ctx, args) => {
},
});
export const processPayment = action({
handler: async (ctx, args) => {
await ctx.scheduler.runAfter(0, internal.users.chargeUserInternal, {
userId: args.userId,
amount: args.amount,
});
},
});
Internal Functions
Use internalQuery, internalMutation, and internalAction for functions that should only be called from backend code:
export const internalHelper = internalMutation({
args: { },
handler: async (ctx, args) => {
},
});