INTEGRITY Dokumentace

Plánování úloh

Plánujte úlohy ke spuštění v budoucnu: ať už jde o sekundy od teď, konkrétní datum a čas, nebo opakující se plán typu cron. Naplánované úlohy přežijí restart agenta a jsou trvale uloženy v SQLite.

Naplánované úlohy dokážou vše, co požadavek nebo zpráva od uživatele: odesílat požadavky, dotazovat se databází, odesílat e-maily, číst a zapisovat stav. Naplánované úlohy mohou vyvolat libovolnou běžnou metodu vašeho Agentu.

Přehled

Systém plánování podporuje čtyři režimy:

Režim Syntaxe Případ použití
Odložené this.schedule(60, ...) Spuštění za 60 sekund
Naplánováno this.schedule(new Date(...), ...) Spuštění v konkrétním čase
Cron this.schedule("0 8 * * *", ...) Spouštění podle opakovaného plánu
Interval this.scheduleEvery(30, ...) Spouštění každých 30 sekund

Plánování pod kapotou využívá Alarmy Durable Object k probuzení agenta ve správný okamžik. Úlohy se ukládají do tabulky SQLite a spouštějí se v pořadí.

Rychlý start

import { Agent } from "agents";

export class ReminderAgent extends Agent {
	async onRequest(request) {
		const url = new URL(request.url);

		// Schedule in 30 seconds
		await this.schedule(30, "sendReminder", {
			message: "Check your email",
		});

		// Schedule at specific time
		await this.schedule(new Date("2025-02-01T09:00:00Z"), "sendReminder", {
			message: "Monthly report due",
		});

		// Schedule recurring (every day at 8am)
		await this.schedule("0 8 * * *", "dailyDigest", {
			userId: url.searchParams.get("userId"),
		});

		return new Response("Scheduled!");
	}

	async sendReminder(payload) {
		console.log(`Reminder: ${payload.message}`);
		// Send notification, email, etc.
	}

	async dailyDigest(payload) {
		console.log(`Sending daily digest to ${payload.userId}`);
		// Generate and send digest
	}
}
import { Agent } from "agents";

export class ReminderAgent extends Agent {
	async onRequest(request: Request) {
		const url = new URL(request.url);

		// Schedule in 30 seconds
		await this.schedule(30, "sendReminder", {
			message: "Check your email",
		});

		// Schedule at specific time
		await this.schedule(new Date("2025-02-01T09:00:00Z"), "sendReminder", {
			message: "Monthly report due",
		});

		// Schedule recurring (every day at 8am)
		await this.schedule("0 8 * * *", "dailyDigest", {
			userId: url.searchParams.get("userId"),
		});

		return new Response("Scheduled!");
	}

	async sendReminder(payload: { message: string }) {
		console.log(`Reminder: ${payload.message}`);
		// Send notification, email, etc.
	}

	async dailyDigest(payload: { userId: string }) {
		console.log(`Sending daily digest to ${payload.userId}`);
		// Generate and send digest
	}
}

Režimy plánování

Odložené spuštění

Předejte číslo, chcete-li naplánovat spuštění úlohy po prodlevě v sekundy:

// Run in 10 seconds
await this.schedule(10, "processTask", { taskId: "123" });

// Run in 5 minutes (300 seconds)
await this.schedule(300, "sendFollowUp", { email: "[email protected]" });

// Run in 1 hour
await this.schedule(3600, "checkStatus", { orderId: "abc" });
// Run in 10 seconds
await this.schedule(10, "processTask", { taskId: "123" });

// Run in 5 minutes (300 seconds)
await this.schedule(300, "sendFollowUp", { email: "[email protected]" });

// Run in 1 hour
await this.schedule(3600, "checkStatus", { orderId: "abc" });

Případy použití:

Naplánované spuštění

Předejte Date objekt pro naplánování úlohy na konkrétní čas:

// Run tomorrow at noon
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setHours(12, 0, 0, 0);
await this.schedule(tomorrow, "sendReminder", { message: "Meeting time!" });

// Run at a specific timestamp
await this.schedule(new Date("2025-06-15T14:30:00Z"), "triggerEvent", {
	eventId: "conference-2025",
});

// Run in 2 hours using Date math
const twoHoursFromNow = new Date(Date.now() + 2 * 60 * 60 * 1000);
await this.schedule(twoHoursFromNow, "checkIn", {});
// Run tomorrow at noon
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setHours(12, 0, 0, 0);
await this.schedule(tomorrow, "sendReminder", { message: "Meeting time!" });

// Run at a specific timestamp
await this.schedule(new Date("2025-06-15T14:30:00Z"), "triggerEvent", {
	eventId: "conference-2025",
});

// Run in 2 hours using Date math
const twoHoursFromNow = new Date(Date.now() + 2 * 60 * 60 * 1000);
await this.schedule(twoHoursFromNow, "checkIn", {});

Případy použití:

Opakující se (cron)

Předejte řetězec cron výrazu pro opakované plány:

// Every day at 8:00 AM
await this.schedule("0 8 * * *", "dailyReport", {});

// Every hour
await this.schedule("0 * * * *", "hourlyCheck", {});

// Every Monday at 9:00 AM
await this.schedule("0 9 * * 1", "weeklySync", {});

// Every 15 minutes
await this.schedule("*/15 * * * *", "pollForUpdates", {});

// First day of every month at midnight
await this.schedule("0 0 1 * *", "monthlyCleanup", {});
// Every day at 8:00 AM
await this.schedule("0 8 * * *", "dailyReport", {});

// Every hour
await this.schedule("0 * * * *", "hourlyCheck", {});

// Every Monday at 9:00 AM
await this.schedule("0 9 * * 1", "weeklySync", {});

// Every 15 minutes
await this.schedule("*/15 * * * *", "pollForUpdates", {});

// First day of every month at midnight
await this.schedule("0 0 1 * *", "monthlyCleanup", {});

Syntaxe cron: minute hour day month weekday

Pole Hodnoty Speciální znaky
Minuta 0-59 * , - /
Hodina 0-23 * , - /
Den v měsíci 1-31 * , - /
Měsíc 1-12 * , - /
Den v týdnu 0-6 (0=neděle) * , - /

Běžné vzory:

"* * * * *"; // Every minute
"*/5 * * * *"; // Every 5 minutes
"0 * * * *"; // Every hour (on the hour)
"0 0 * * *"; // Every day at midnight
"0 8 * * 1-5"; // Weekdays at 8am
"0 0 * * 0"; // Every Sunday at midnight
"0 0 1 * *"; // First of every month
"* * * * *"; // Every minute
"*/5 * * * *"; // Every 5 minutes
"0 * * * *"; // Every hour (on the hour)
"0 0 * * *"; // Every day at midnight
"0 8 * * 1-5"; // Weekdays at 8am
"0 0 * * 0"; // Every Sunday at midnight
"0 0 1 * *"; // First of every month

Případy použití:

Plány cron jsou ve výchozím nastavení idempotentní: volání schedule() se stejným výrazem cron, callbackem a payloadem opakovaně vrátí existující plán místo vytvoření duplicity. Díky tomu je bezpečné nastavovat plány cron v onStart().

Interval

Použijte scheduleEvery() ke spouštění úlohy v pevných intervalech (v sekundách). Na rozdíl od cronu intervaly podporují přesnost pod jednu minutu i libovolnou délku trvání:

// Poll every 30 seconds
await this.scheduleEvery(30, "poll", { source: "api" });

// Health check every 45 seconds
await this.scheduleEvery(45, "healthCheck", {});

// Sync every 90 seconds (1.5 minutes - cannot be expressed in cron)
await this.scheduleEvery(90, "syncData", { destination: "warehouse" });
// Poll every 30 seconds
await this.scheduleEvery(30, "poll", { source: "api" });

// Health check every 45 seconds
await this.scheduleEvery(45, "healthCheck", {});

// Sync every 90 seconds (1.5 minutes - cannot be expressed in cron)
await this.scheduleEvery(90, "syncData", { destination: "warehouse" });

Klíčové rozdíly oproti cronu:

Funkce Cron Interval
Minimální granularita 1 minuta 1 sekunda
Libovolné intervaly Ne (musí odpovídat cron vzoru) Ano
Pevný plán Ano (například "každý den v 8 hodin ráno") Ne (relativně k začátku)
Prevence překrývání Ne Ano (vestavěné)

Idempotence:

scheduleEvery() je idempotentní vůči kombinaci názvu callbacku, intervalu a payloadu: opakované volání se stejnými argumenty nevytváří duplicitní plány. Díky tomu je bezpečné volat ji v onStart(), který se spouští při každém probuzení Durable Object:

class MyAgent extends Agent {
	async onStart() {
		// Safe to call on every wake — only one schedule is created
		await this.scheduleEvery(30, "poll", { source: "api" });
	}
}
class MyAgent extends Agent {
	async onStart() {
		// Safe to call on every wake — only one schedule is created
		await this.scheduleEvery(30, "poll", { source: "api" });
	}
}

Jiný interval nebo payload vytvoří nový, nezávislý plán.

Prevence překrývání:

Pokud callback trvá déle než daný interval, další spuštění se přeskočí (nezařadí se do fronty). Tím se zabrání nekontrolovanému růstu spotřeby zdrojů:

class PollingAgent extends Agent {
	async poll() {
		// If this takes 45 seconds and interval is 30 seconds,
		// the next poll is skipped (with a warning logged)
		const data = await slowExternalApi();
		await this.processData(data);
	}
}

// Set up 30-second interval
await this.scheduleEvery(30, "poll", {});
class PollingAgent extends Agent {
	async poll() {
		// If this takes 45 seconds and interval is 30 seconds,
		// the next poll is skipped (with a warning logged)
		const data = await slowExternalApi();
		await this.processData(data);
	}
}

// Set up 30-second interval
await this.scheduleEvery(30, "poll", {});

Když dojde k přeskočení, uvidíte v logu varování:

Skipping interval schedule abc123: previous execution still running

Odolnost vůči chybám:

Pokud callback vyvolá chybu, interval pokračuje, selže pouze toto spuštění:

class SyncAgent extends Agent {
	async syncData() {
		// Even if this throws, the interval keeps running
		const response = await fetch("https://api.example.com/data");
		if (!response.ok) throw new Error("Sync failed");
		// ...
	}
}
class SyncAgent extends Agent {
	async syncData() {
		// Even if this throws, the interval keeps running
		const response = await fetch("https://api.example.com/data");
		if (!response.ok) throw new Error("Sync failed");
		// ...
	}
}

Případy použití:

Správa naplánovaných úloh

Získat plán

Načtěte naplánovanou úlohu podle jejího ID:

const schedule = await this.getScheduleById(scheduleId);

if (schedule) {
	console.log(
		`Task ${schedule.id} will run at ${new Date(schedule.time * 1000)}`,
	);
	console.log(`Callback: ${schedule.callback}`);
	console.log(`Type: ${schedule.type}`); // "scheduled" | "delayed" | "cron" | "interval"
} else {
	console.log("Schedule not found");
}
const schedule = await this.getScheduleById(scheduleId);

if (schedule) {
	console.log(
		`Task ${schedule.id} will run at ${new Date(schedule.time * 1000)}`,
	);
	console.log(`Callback: ${schedule.callback}`);
	console.log(`Type: ${schedule.type}`); // "scheduled" | "delayed" | "cron" | "interval"
} else {
	console.log("Schedule not found");
}

Vypsat plány

Dotázat se na naplánované úlohy s volitelnými filtry:

// Get all scheduled tasks
const allSchedules = await this.listSchedules();

// Get only cron jobs
const cronJobs = await this.listSchedules({ type: "cron" });

// Get tasks in the next hour
const upcoming = await this.listSchedules({
	timeRange: {
		start: new Date(),
		end: new Date(Date.now() + 60 * 60 * 1000),
	},
});

// Get a specific task by ID
const specific = await this.listSchedules({ id: "abc123" });

// Combine filters
const upcomingCronJobs = await this.listSchedules({
	type: "cron",
	timeRange: {
		start: new Date(),
		end: new Date(Date.now() + 24 * 60 * 60 * 1000),
	},
});
// Get all scheduled tasks
const allSchedules = await this.listSchedules();

// Get only cron jobs
const cronJobs = await this.listSchedules({ type: "cron" });

// Get tasks in the next hour
const upcoming = await this.listSchedules({
	timeRange: {
		start: new Date(),
		end: new Date(Date.now() + 60 * 60 * 1000),
	},
});

// Get a specific task by ID
const specific = await this.listSchedules({ id: "abc123" });

// Combine filters
const upcomingCronJobs = await this.listSchedules({
	type: "cron",
	timeRange: {
		start: new Date(),
		end: new Date(Date.now() + 24 * 60 * 60 * 1000),
	},
});

Zrušení plánu

Odeberte naplánovanou úlohu před jejím spuštěním:

const cancelled = await this.cancelSchedule(scheduleId);

if (cancelled) {
	console.log("Schedule cancelled successfully");
} else {
	console.log("Schedule not found (may have already executed)");
}
const cancelled = await this.cancelSchedule(scheduleId);

if (cancelled) {
	console.log("Schedule cancelled successfully");
} else {
	console.log("Schedule not found (may have already executed)");
}

Příklad: zrušitelné připomínky

class ReminderAgent extends Agent {
	async setReminder(userId, message, delaySeconds) {
		const schedule = await this.schedule(delaySeconds, "sendReminder", {
			userId,
			message,
		});

		// Store the schedule ID so user can cancel later
		this.sql`
      INSERT INTO user_reminders (user_id, schedule_id, message)
      VALUES (${userId}, ${schedule.id}, ${message})
    `;

		return schedule.id;
	}

	async cancelReminder(scheduleId) {
		const cancelled = await this.cancelSchedule(scheduleId);

		if (cancelled) {
			this.sql`DELETE FROM user_reminders WHERE schedule_id = ${scheduleId}`;
		}

		return cancelled;
	}

	async sendReminder(payload) {
		// Send the reminder...

		// Clean up the record
		this.sql`DELETE FROM user_reminders WHERE user_id = ${payload.userId}`;
	}
}
class ReminderAgent extends Agent {
	async setReminder(userId: string, message: string, delaySeconds: number) {
		const schedule = await this.schedule(delaySeconds, "sendReminder", {
			userId,
			message,
		});

		// Store the schedule ID so user can cancel later
		this.sql`
      INSERT INTO user_reminders (user_id, schedule_id, message)
      VALUES (${userId}, ${schedule.id}, ${message})
    `;

		return schedule.id;
	}

	async cancelReminder(scheduleId: string) {
		const cancelled = await this.cancelSchedule(scheduleId);

		if (cancelled) {
			this.sql`DELETE FROM user_reminders WHERE schedule_id = ${scheduleId}`;
		}

		return cancelled;
	}

	async sendReminder(payload: { userId: string; message: string }) {
		// Send the reminder...

		// Clean up the record
		this.sql`DELETE FROM user_reminders WHERE user_id = ${payload.userId}`;
	}
}

Objekt Schedule

Při vytvoření nebo načtení plánu získáte Schedule objekt:

type Schedule<T> = {
	id: string; // Unique identifier
	callback: string; // Method name to call
	payload: T; // Data passed to the callback
	time: number; // Unix timestamp (seconds) of next execution
} & (
	| { type: "scheduled" } // One-time at specific date
	| { type: "delayed"; delayInSeconds: number } // One-time after delay
	| { type: "cron"; cron: string } // Recurring (cron expression)
	| { type: "interval"; intervalSeconds: number } // Recurring (fixed interval)
);

Příklad:

const schedule = await this.schedule(60, "myTask", { foo: "bar" });

console.log(schedule);
// {
//   id: "abc123xyz",
//   callback: "myTask",
//   payload: { foo: "bar" },
//   time: 1706745600,
//   type: "delayed",
//   delayInSeconds: 60
// }
const schedule = await this.schedule(60, "myTask", { foo: "bar" });

console.log(schedule);
// {
//   id: "abc123xyz",
//   callback: "myTask",
//   payload: { foo: "bar" },
//   time: 1706745600,
//   type: "delayed",
//   delayInSeconds: 60
// }

Vzory

Přeplánování z callbacků

Pro dynamické opakující se plány naplánujte další spuštění přímo v rámci callbacku:

class PollingAgent extends Agent {
	async startPolling(intervalSeconds) {
		await this.schedule(intervalSeconds, "poll", { interval: intervalSeconds });
	}

	async poll(payload) {
		try {
			const data = await fetch("https://api.example.com/updates");
			await this.processUpdates(await data.json());
		} catch (error) {
			console.error("Polling failed:", error);
		}

		// Schedule the next poll (regardless of success/failure)
		await this.schedule(payload.interval, "poll", payload);
	}

	async stopPolling() {
		// Cancel all polling schedules
		const schedules = await this.listSchedules({ type: "delayed" });
		for (const schedule of schedules) {
			if (schedule.callback === "poll") {
				await this.cancelSchedule(schedule.id);
			}
		}
	}
}
class PollingAgent extends Agent {
	async startPolling(intervalSeconds: number) {
		await this.schedule(intervalSeconds, "poll", { interval: intervalSeconds });
	}

	async poll(payload: { interval: number }) {
		try {
			const data = await fetch("https://api.example.com/updates");
			await this.processUpdates(await data.json());
		} catch (error) {
			console.error("Polling failed:", error);
		}

		// Schedule the next poll (regardless of success/failure)
		await this.schedule(payload.interval, "poll", payload);
	}

	async stopPolling() {
		// Cancel all polling schedules
		const schedules = await this.listSchedules({ type: "delayed" });
		for (const schedule of schedules) {
			if (schedule.callback === "poll") {
				await this.cancelSchedule(schedule.id);
			}
		}
	}
}

Opakování s exponenciálním prodlením

class RetryAgent extends Agent {
	async attemptTask(payload) {
		try {
			await this.doWork(payload.taskId);
			console.log(
				`Task ${payload.taskId} succeeded on attempt ${payload.attempt}`,
			);
		} catch (error) {
			if (payload.attempt >= payload.maxAttempts) {
				console.error(
					`Task ${payload.taskId} failed after ${payload.maxAttempts} attempts`,
				);
				return;
			}

			// Exponential backoff: 2^attempt seconds (2s, 4s, 8s, 16s...)
			const delaySeconds = Math.pow(2, payload.attempt);

			await this.schedule(delaySeconds, "attemptTask", {
				...payload,
				attempt: payload.attempt + 1,
			});

			console.log(`Retrying task ${payload.taskId} in ${delaySeconds}s`);
		}
	}

	async doWork(taskId) {
		// Your actual work here
	}
}
class RetryAgent extends Agent {
	async attemptTask(payload: {
		taskId: string;
		attempt: number;
		maxAttempts: number;
	}) {
		try {
			await this.doWork(payload.taskId);
			console.log(
				`Task ${payload.taskId} succeeded on attempt ${payload.attempt}`,
			);
		} catch (error) {
			if (payload.attempt >= payload.maxAttempts) {
				console.error(
					`Task ${payload.taskId} failed after ${payload.maxAttempts} attempts`,
				);
				return;
			}

			// Exponential backoff: 2^attempt seconds (2s, 4s, 8s, 16s...)
			const delaySeconds = Math.pow(2, payload.attempt);

			await this.schedule(delaySeconds, "attemptTask", {
				...payload,
				attempt: payload.attempt + 1,
			});

			console.log(`Retrying task ${payload.taskId} in ${delaySeconds}s`);
		}
	}

	async doWork(taskId: string) {
		// Your actual work here
	}
}

Agenti s automatickým sebezničením

Bezpečně můžete volat this.destroy() zevnitř naplánovaného callbacku:

class TemporaryAgent extends Agent {
	async onStart() {
		// Self-destruct in 24 hours
		await this.schedule(24 * 60 * 60, "cleanup", {});
	}

	async cleanup() {
		// Perform final cleanup
		console.log("Agent lifetime expired, cleaning up...");

		// This is safe to call from a scheduled callback
		await this.destroy();
	}
}
class TemporaryAgent extends Agent {
	async onStart() {
		// Self-destruct in 24 hours
		await this.schedule(24 * 60 * 60, "cleanup", {});
	}

	async cleanup() {
		// Perform final cleanup
		console.log("Agent lifetime expired, cleaning up...");

		// This is safe to call from a scheduled callback
		await this.destroy();
	}
}

plánování s podporou AI

SDK obsahuje nástroje pro rozpoznávání požadavků na plánování v přirozeném jazyce pomocí AI.

getSchedulePrompt()

Vrací systémový prompt pro parsování přirozeného jazyka do parametrů plánování:

import { getSchedulePrompt, scheduleSchema } from "agents";
import { generateObject } from "ai";
import { openai } from "@ai-sdk/openai";

class SmartScheduler extends Agent {
	async parseScheduleRequest(userInput) {
		const result = await generateObject({
			model: openai("gpt-4o"),
			system: getSchedulePrompt({ date: new Date() }),
			prompt: userInput,
			schema: scheduleSchema,
		});

		return result.object;
	}

	async handleUserRequest(input) {
		// Parse: "remind me to call mom tomorrow at 3pm"
		const parsed = await this.parseScheduleRequest(input);

		// parsed = {
		//   description: "call mom",
		//   when: {
		//     type: "scheduled",
		//     date: "2025-01-30T15:00:00Z"
		//   }
		// }

		if (parsed.when.type === "scheduled" && parsed.when.date) {
			await this.schedule(new Date(parsed.when.date), "sendReminder", {
				message: parsed.description,
			});
		} else if (parsed.when.type === "delayed" && parsed.when.delayInSeconds) {
			await this.schedule(parsed.when.delayInSeconds, "sendReminder", {
				message: parsed.description,
			});
		} else if (parsed.when.type === "cron" && parsed.when.cron) {
			await this.schedule(parsed.when.cron, "sendReminder", {
				message: parsed.description,
			});
		}
	}

	async sendReminder(payload) {
		console.log(`Reminder: ${payload.message}`);
	}
}
import { getSchedulePrompt, scheduleSchema } from "agents";
import { generateObject } from "ai";
import { openai } from "@ai-sdk/openai";

class SmartScheduler extends Agent {
	async parseScheduleRequest(userInput: string) {
		const result = await generateObject({
			model: openai("gpt-4o"),
			system: getSchedulePrompt({ date: new Date() }),
			prompt: userInput,
			schema: scheduleSchema,
		});

		return result.object;
	}

	async handleUserRequest(input: string) {
		// Parse: "remind me to call mom tomorrow at 3pm"
		const parsed = await this.parseScheduleRequest(input);

		// parsed = {
		//   description: "call mom",
		//   when: {
		//     type: "scheduled",
		//     date: "2025-01-30T15:00:00Z"
		//   }
		// }

		if (parsed.when.type === "scheduled" && parsed.when.date) {
			await this.schedule(new Date(parsed.when.date), "sendReminder", {
				message: parsed.description,
			});
		} else if (parsed.when.type === "delayed" && parsed.when.delayInSeconds) {
			await this.schedule(parsed.when.delayInSeconds, "sendReminder", {
				message: parsed.description,
			});
		} else if (parsed.when.type === "cron" && parsed.when.cron) {
			await this.schedule(parsed.when.cron, "sendReminder", {
				message: parsed.description,
			});
		}
	}

	async sendReminder(payload: { message: string }) {
		console.log(`Reminder: ${payload.message}`);
	}
}

scheduleSchema

Schéma Zod pro ověřování zpracovaných dat o plánování. Používá diskriminovanou unii podle when.type aby každá varianta obsahovala jen pole, která potřebuje:

import { scheduleSchema } from "agents";

// The schema is a discriminated union:
// {
//   description: string,
//   when:
//     | { type: "scheduled", date: string }       // ISO 8601 date string
//     | { type: "delayed", delayInSeconds: number }
//     | { type: "cron", cron: string }
//     | { type: "no-schedule" }
// }
import { scheduleSchema } from "agents";

// The schema is a discriminated union:
// {
//   description: string,
//   when:
//     | { type: "scheduled", date: string }       // ISO 8601 date string
//     | { type: "delayed", delayInSeconds: number }
//     | { type: "cron", cron: string }
//     | { type: "no-schedule" }
// }

Plánování vs. Queue vs. Workflows

Funkce Queue Plánování Workflows
Kdy Ihned (FIFO) Budoucí čas Budoucí čas
Spuštění Sekvenční V naplánovaný čas Vícekrokové
Opakování Vestavěné Vestavěné Automaticky
Perzistence SQLite SQLite Workflow engine
Opakující se Ne Ano (cron) Ne (použijte plánování)
Komplexní logika Ne Ne Ano
Lidské schválení Ne Ne Ano

Používejte Queue, když:

Používejte Plánování, když:

Používejte Workflows, když:

Referenční dokumentace API

schedule()

async schedule<T>(
  when: Date | string | number,
  callback: keyof this,
  payload?: T,
  options?: { retry?: RetryOptions; idempotent?: boolean }
): Promise<Schedule<T>>

Naplánujte úlohu k budoucímu spuštění.

Parametry:

Vrací: Schedule objekt s podrobnostmi úlohy

Idempotence:

Plány cron jsou ve výchozím nastavení idempotentní: volání schedule("0 * * * *", "tick") vícekrát se stejným callbackem, cron výrazem a payloadem vrátí existující plán místo vytvoření duplicity. Nastavte idempotent: false k přepsání tohoto chování.

Pro odložené a na datu založené plány nastavte idempotent: true k zapojení do stejného chování deduplikace (shoda podle callbacku a payloadu). To je užitečné zejména při volání schedule() v onStart() abyste zabránili hromadění duplicitních řádků při restartech Durable Object:

class MyAgent extends Agent {
	async onStart() {
		// Without idempotent: true, this creates a new row on every DO restart
		await this.schedule(3600, "hourlyCleanup", {}, { idempotent: true });
	}
}
class MyAgent extends Agent {
	async onStart() {
		// Without idempotent: true, this creates a new row on every DO restart
		await this.schedule(3600, "hourlyCleanup", {}, { idempotent: true });
	}
}

scheduleEvery()

async scheduleEvery<T>(
  intervalSeconds: number,
  callback: keyof this,
  payload?: T,
  options?: { retry?: RetryOptions }
): Promise<Schedule<T>>

Naplánujte úlohu, která se bude opakovaně spouštět v pevném intervalu.

Parametry:

Vrací: Schedule objekt s type: "interval"

Chování:

getScheduleById()

async getScheduleById(id: string): Promise<Schedule<unknown> | undefined>

Získat naplánovanou úlohu podle ID. Vrátí undefined pokud nebylo nalezeno. Tato metoda funguje jak u agentů nejvyšší úrovně, tak u podřízených agentů.

listSchedules()

async listSchedules(criteria?: {
  id?: string;
  type?: "scheduled" | "delayed" | "cron" | "interval";
  timeRange?: { start?: Date; end?: Date };
}): Promise<Schedule<unknown>[]>

Získat naplánované úlohy odpovídající zadaným kritériím. Tato metoda funguje jak u agentů nejvyšší úrovně, tak u podřízených agentů.

getSchedule()

getSchedule<T>(id: string): Schedule<T> | undefined

Zastaralé. Synchronně získá naplánovanou úlohu podle ID. Tato metoda funguje pouze u agentů nejvyšší úrovně. Použijte await this.getScheduleById(id) místo toho.

getSchedules()

getSchedules<T>(criteria?: {
  id?: string;
  type?: "scheduled" | "delayed" | "cron" | "interval";
  timeRange?: { start?: Date; end?: Date };
}): Schedule<T>[]

Zastaralé. Synchronně získá naplánované úlohy odpovídající zadaným kritériím. Tato metoda funguje pouze u agentů nejvyšší úrovně. Použijte await this.listSchedules(criteria) místo toho.

cancelSchedule()

async cancelSchedule(id: string): Promise<boolean>

Zruší naplánovanou úlohu. Vrátí true pokud je zrušeno, false pokud nebylo nalezeno.

keepAlive()

async keepAlive(): Promise<() => void>

Zabránit vyřazení Durable Object z paměti kvůli nečinnosti podržením reference na 30sekundový heartbeat vázaný na alarm. Vrací funkci disposer, která po zavolání heartbeat uvolní. Disposer je idempotentní: jeho opakované volání je bezpečné.

Po dokončení práce vždy zavolejte disposer, jinak bude heartbeat pokračovat donekonečna.

const dispose = await this.keepAlive();
try {
	// Long-running work that must not be interrupted
	const result = await longRunningComputation();
	await sendResults(result);
} finally {
	dispose();
}
const dispose = await this.keepAlive();
try {
	// Long-running work that must not be interrupted
	const result = await longRunningComputation();
	await sendResults(result);
} finally {
	dispose();
}

keepAliveWhile()

async keepAliveWhile<T>(fn: () => Promise<T>): Promise<T>

Spusťte asynchronní funkci a přitom udržujte Durable Object naživu. Heartbeat se automaticky spustí před spuštěním funkce a zastaví se po jejím dokončení (ať už uspěje, nebo vyvolá chybu). Vrací hodnotu, kterou funkce vrátí.

Toto je doporučený způsob, jak používat keepAlive : zaručuje úklid.

const result = await this.keepAliveWhile(async () => {
	const data = await longRunningComputation();
	return data;
});
const result = await this.keepAliveWhile(async () => {
	const data = await longRunningComputation();
	return data;
});

Udržování agenta naživu

Durable Objects se po období nečinnosti vyřadí z paměti (obvykle po 70 až 140 sekundách bez příchozích požadavků, zpráv WebSocketu nebo alarmů). Během dlouhotrvajících operací, jako je streamování odpovědí LLM, čekání na externí API nebo provádění vícekrokových výpočtů, může být agent vyřazen z paměti uprostřed práce.

keepAlive() tomu brání tím, že drží referenci na heartbeat v paměti a přímo využívá systém alarmů Durable Object. Samotné spuštění alarmu resetuje časovač nečinnosti.

Více souběžných volajících

Každý keepAlive() volání vrátí nezávislý disposer:

const dispose1 = await this.keepAlive();
const dispose2 = await this.keepAlive();

// Both heartbeats are active
dispose1(); // Only cancels the first heartbeat
// Agent is still alive via dispose2's heartbeat

dispose2(); // Now the agent can go idle
const dispose1 = await this.keepAlive();
const dispose2 = await this.keepAlive();

// Both heartbeats are active
dispose1(); // Only cancels the first heartbeat
// Agent is still alive via dispose2's heartbeat

dispose2(); // Now the agent can go idle

AIChatAgent

AIChatAgent automaticky volá keepAlive() během streamovaných odpovědí. Nemusíte jej přidávat sami, pokud používáte AIChatAgent : každý stream LLM je ve výchozím nastavení chráněn před vyřazením z paměti kvůli nečinnosti.

Kdy použít keepAlive

Scénář Použít keepAlive?
Streamování odpovědí LLM přes AIChatAgent Ne: již je to vestavěné
Dlouhotrvající výpočet ve vlastním Agentovi Ano
Čekání na pomalé externí volání API Ano
Vícekrokové spouštění nástrojů Ano
Krátké handlery typu request-response Ne: není to potřeba
Práce na pozadí prostřednictvím plánování nebo workflow Ne: alarmy již udržují DO aktivní

Limity

Další kroky

Push notifikace

Odesílejte push oznámení pomocí plánování a web-push.

Zařazování úloh do fronty

Okamžité zpracování úloh na pozadí.

Spouštění Workflows

Trvalé vícekrokové zpracování na pozadí.

Agents API

Kompletní referenční dokumentace API pro Agents SDK.