Durable Objects のアラームを使うと、将来の時刻に Durable Object を起こすスケジュールを設定できます。アラームの予定時刻になると、alarm() ハンドラーメソッドが呼ばれます。アラームの変更は Storage API で行い、アラーム操作はほかのストレージ操作と同じ規則に従います。
特に次の点に注意してください。
- 各 Durable Object は、
setAlarm()を呼ぶことで、同時に 1 つのアラームだけをスケジュールできます。 - アラームは少なくとも 1 回(at-least-once)の実行が保証され、
alarm()ハンドラーが例外を投げると自動で再試行されます。 - 再試行は指数バックオフで行われ、最初の失敗から 2 秒の遅延で始まり、最大 6 回まで再試行できます。
アラームは、Durable Objects の上にキューや作業のバッチ処理などの分散プリミティブを作るために使えます。また、受信リクエストに頼らずに Durable Object 内の処理を完了させる仕組みにもなります。完全な例は Alarms API を使う を参照してください。
各 Durable Object が同時に持てるアラームは 1 つだけですが、イベントの予定をストレージに保存し、alarm() ハンドラーで期限到来のイベントを処理してから、次のイベント向けに自分自身を再スケジュールすれば、多数の予定イベントと繰り返しイベントを管理できます。
import { DurableObject } from "cloudflare:workers";
export class AgentServer extends DurableObject {
// Schedule a one-time or recurring event
async scheduleEvent(id, runAt, repeatMs = null) {
await this.ctx.storage.put(`event:${id}`, { id, runAt, repeatMs });
const currentAlarm = await this.ctx.storage.getAlarm();
if (!currentAlarm || runAt < currentAlarm) {
await this.ctx.storage.setAlarm(runAt);
}
}
async alarm() {
const now = Date.now();
const events = await this.ctx.storage.list({ prefix: "event:" });
let nextAlarm = null;
for (const [key, event] of events) {
if (event.runAt <= now) {
await this.processEvent(event);
if (event.repeatMs) {
event.runAt = now + event.repeatMs;
await this.ctx.storage.put(key, event);
} else {
await this.ctx.storage.delete(key);
}
}
// Track the next event time
if (event.runAt > now && (!nextAlarm || event.runAt < nextAlarm)) {
nextAlarm = event.runAt;
}
}
if (nextAlarm) await this.ctx.storage.setAlarm(nextAlarm);
}
async processEvent(event) {
// Your event handling logic here
}
}-
getAlarm():number | null-
アラームが設定されている場合は、現在設定されているアラーム時刻を、UNIX epoch からの経過ミリ秒数として返します。それ以外の場合は
nullを返します。 -
alarmの実行中にgetAlarmを呼ぶと、alarmハンドラーの開始以降にsetAlarmも呼んでいない限り、nullを返します。
-
-
setAlarm(scheduledTimeMs:number)void- アラームを実行する時刻を設定します。時刻は UNIX epoch からの経過ミリ秒数で指定します。
- すでにスケジュールがある状態で
setAlarmを呼ぶと、既存のアラームを上書きします。
-
deleteAlarm():void-
現在アラームが設定されている場合、そのアラームを解除します。
-
alarm()ハンドラー内でdeleteAlarm()を呼ぶと、ベストエフォートで再試行を止められることがありますが、保証はありません。
-
-
alarm(alarmInfo:Object)void-
スケジュールしたアラーム時刻に達したとき、システムから呼ばれます。
-
任意のパラメーター
alarmInfoオブジェクトには、次の 2 つのプロパティがあります。retryCountnumber: このアラームイベントが再試行された回数です。isRetryboolean: アラームが再試行されたかどうかを示す真偽値です。このアラームイベントが再試行である場合はtrueです。
-
1 つの Durable Object インスタンスにつき、同時に実行される
alarm()は常に 1 つだけです。 -
alarm()ハンドラーは少なくとも 1 回(at-least-once)の実行が保証され、失敗時は 2 秒の遅延から始まる指数バックオフで、最大 6 回まで再試行されます。これは直近のsetAlarm()呼び出しにだけ適用されます。メソッドがキャッチされない例外で失敗した場合に再試行されます。 -
このメソッドは
asyncにできます。
-
この例では、Durable Object 内で setAlarm(timestamp) メソッドによるアラーム設定と、alarm() ハンドラーによるアラーム処理の両方を示します。
- アラームが発火するたびに、
alarm()ハンドラーが 1 回呼ばれます。 - 予期しないエラーで Durable Object が終了した場合、
alarm()ハンドラーは別のマシンで再インスタンス化されることがあります。 - 短い遅延のあと、
alarm()ハンドラーは別のマシン上で先頭から実行されます。
import { DurableObject } from "cloudflare:workers";
export default {
async fetch(request, env) {
return await env.ALARM_EXAMPLE.getByName("foo").fetch(request);
},
};
const SECONDS = 1000;
export class AlarmExample extends DurableObject {
constructor(ctx, env) {
super(ctx, env);
this.storage = ctx.storage;
}
async fetch(request) {
// If there is no alarm currently set, set one for 10 seconds from now
let currentAlarm = await this.storage.getAlarm();
if (currentAlarm == null) {
this.storage.setAlarm(Date.now() + 10 * SECONDS);
}
}
async alarm() {
// The alarm handler will be invoked whenever an alarm fires.
// You can use this to do work, read from the Storage API, make HTTP calls
// and set future alarms to run using this.storage.setAlarm() from within this handler.
}
}import time
from workers import DurableObject, WorkerEntrypoint
class Default(WorkerEntrypoint):
async def fetch(self, request):
return await self.env.ALARM_EXAMPLE.getByName("foo").fetch(request)
SECONDS = 1000
class AlarmExample(DurableObject):
def __init__(self, ctx, env):
super().__init__(ctx, env)
self.storage = ctx.storage
async def fetch(self, request):
# If there is no alarm currently set, set one for 10 seconds from now
current_alarm = await self.storage.getAlarm()
if current_alarm is None:
self.storage.setAlarm(int(time.time() * 1000) + 10 * SECONDS)
async def alarm(self):
# The alarm handler will be invoked whenever an alarm fires.
# You can use this to do work, read from the Storage API, make HTTP calls
# and set future alarms to run using self.storage.setAlarm() from within this handler.
pass次の例では、alarmInfo プロパティを使い、そのアラームイベントが以前に試行されたかどうかを判別します。
class MyDurableObject extends DurableObject {
async alarm(alarmInfo) {
if (alarmInfo?.retryCount != 0) {
console.log(
"This alarm event has been attempted ${alarmInfo?.retryCount} times before.",
);
}
}
}class MyDurableObject(DurableObject):
async def alarm(self, alarm_info):
if alarm_info and alarm_info.get('retryCount', 0) != 0:
print(f"This alarm event has been attempted {alarm_info.get('retryCount')} times before.")- エンドツーエンドの例で Alarms API の使い方 を確認します。
- Durable Objects アラームの発表ブログ記事 ↗ を読みます。
- Durable Objects の Storage API ドキュメントを確認します。