Scheduler Jobs¶
Run background tasks on a schedule.
Overview¶
Scheduler jobs run periodically outside of game sessions:
import { SchedulerJob, SchedulerJobContext } from '@lands.io/mod-sdk';
class LeaderboardUpdateJob extends SchedulerJob {
readonly cronExpression = '0 0 * * * *'; // Every hour
async execute(context: SchedulerJobContext): Promise<void> {
const topPlayers = await context.storage.getOrderedDesc(
'players',
'elo',
100
);
console.log('Updated leaderboard:', topPlayers.length, 'players');
}
}
SchedulerJob Class¶
Required Properties¶
Required Methods¶
Cron Expression Format¶
┌──────────── second (0-59)
│ ┌────────── minute (0-59)
│ │ ┌──────── hour (0-23)
│ │ │ ┌────── day of month (1-31)
│ │ │ │ ┌──── month (1-12)
│ │ │ │ │ ┌── day of week (0-6, Sunday=0)
│ │ │ │ │ │
* * * * * *
Common Patterns¶
| Expression | Description |
|---|---|
0 0 * * * * |
Every hour |
0 0 */2 * * * |
Every 2 hours |
0 0 0 * * * |
Daily at midnight |
0 0 12 * * * |
Daily at noon |
0 0 0 * * 0 |
Weekly on Sunday |
0 0 0 1 * * |
Monthly on the 1st |
Minimum Interval
Jobs must run at least 1 hour apart to prevent excessive resource usage.
SchedulerJobContext¶
interface SchedulerJobContext {
storage: IModStorage; // Persistent storage
modId: string; // Your mod's ID
}
Example: Weekly Leaderboard Reset¶
import { SchedulerJob, SchedulerJobContext } from '@lands.io/mod-sdk';
export class WeeklyResetJob extends SchedulerJob {
// Run every Sunday at midnight
readonly cronExpression = '0 0 0 * * 0';
async execute(context: SchedulerJobContext): Promise<void> {
// Get top 10 players
const topPlayers = await context.storage.getOrderedDesc(
'players',
'weeklyScore',
10
);
// Award bonuses to top players
for (let i = 0; i < topPlayers.length; i++) {
const bonus = this.calculateBonus(i + 1);
await context.storage.increment(
'players',
topPlayers[i].oderId,
'gems',
bonus
);
}
// Reset weekly scores
// (Implementation depends on your storage API)
console.log(`Weekly reset complete. Awarded ${topPlayers.length} players.`);
}
private calculateBonus(rank: number): number {
const bonuses = [100, 75, 50, 40, 30, 25, 20, 15, 10, 5];
return bonuses[rank - 1] || 0;
}
}
Example: ELO Decay Job¶
export class EloDecayJob extends SchedulerJob {
// Run daily at 3 AM
readonly cronExpression = '0 0 3 * * *';
async execute(context: SchedulerJobContext): Promise<void> {
// Get inactive players (no games in 7 days)
const inactivePlayers = await this.getInactivePlayers(context);
for (const player of inactivePlayers) {
// Apply 1% ELO decay
const decay = Math.floor(player.elo * 0.01);
if (decay > 0) {
await context.storage.increment(
'players',
player.oderId,
'elo',
-decay
);
}
}
console.log(
`Applied ELO decay to ${inactivePlayers.length} inactive players`
);
}
private async getInactivePlayers(context: SchedulerJobContext) {
// Implementation depends on your data model
return [];
}
}
File Organization¶
Place scheduler jobs in a dedicated folder: