跳转到主要内容

Cron container

import { TypeScriptExample, WranglerConfig, PackageManagers, } from "~/components";

Run a short container task every two minutes with a Workers Cron Trigger. The task prints its scheduled time, then exits.

Configure the schedule

name = "cron-container"
main = "src/index.ts"
upload_source_maps = true
compatibility_date = "$today"

[observability]
enabled = true

[triggers]
crons = ["*/2 * * * *"]

[[containers]]
class_name = "CronContainer"
scheduling_policy = "durable_object"

[containers.images.base]
dockerfile = "./Dockerfile"

[[durable_objects.bindings]]
name = "CRON_CONTAINER"
class_name = "CronContainer"

[exports.CronContainer]
type = "durable-object"
storage = "sqlite"

Start and await the task

import { DurableObject } from "cloudflare:workers";

interface Env {
	CRON_CONTAINER: DurableObjectNamespace<CronContainer>;
}

export class CronContainer extends DurableObject<Env> {
	private currentRun: Promise<void> | undefined;

	run(startTime: string): Promise<void> {
		this.currentRun ??= this.runOnce(startTime).finally(() => {
			this.currentRun = undefined;
		});
		return this.currentRun;
	}

	private async runOnce(startTime: string): Promise<void> {
		const container = this.ctx.container!;
		if (!container.running) {
			container.start({
				image: container.images.base,
				instance: "lite",
				enableInternet: false,
				env: { MESSAGE: `Scheduled time: ${startTime}` },
			});
		}
		await container.monitor();
	}
}

export default {
	fetch(): Response {
		return new Response("This Worker runs a scheduled Container task.");
	},
	async scheduled(controller: ScheduledController, env: Env): Promise<void> {
		await env.CRON_CONTAINER.getByName("cron").run(
			new Date(controller.scheduledTime).toISOString(),
		);
	},
} satisfies ExportedHandler<Env>;

All triggers use the same Durable Object. If a run is still active, another trigger waits for that run instead of starting a second task. This example does not queue overlapping runs or guarantee exactly-once execution. Make tasks idempotent when they modify external data.

monitor() reports completion or failure, not HTTP readiness. Keep this task short enough to finish within the Cron Trigger execution limits.

Define the task

FROM alpine:3.20
CMD ["sh", "-c", "printf '%s\\n' \"$MESSAGE\""]

Test the schedule locally

Start a Docker-compatible engine and use Wrangler 4.136.0 or later.

In another terminal, trigger the scheduled handler:

curl 'http://localhost:8787/__scheduled?cron=*/2+*+*+*+*'

Check the container logs for the scheduled time. After deployment, Cron Triggers invoke the handler automatically.