@omar#4289 same as, I am getting the
@omar same as, I am getting the same issue, I have explained my issue
26 Replies
the first time, it is working correctly,
when re-call the water Schedule a second time does the calling schedule 2 times every 2 seconds, same as the next
What is the code in the worker ?
Do you always refer to the same do instance ?
@Harshil Bodara
But whenever I call the schedule, I want to call the alarm only once
export class Water {
id: string | DurableObjectId;
storage: DurableObjectStorage;
doEverySeconds: number;
env: Env;
constructor(state: DurableObjectState, env: Env) { this.storage = state.storage; this.id = state.id; this.doEverySeconds = 2; this.env = env; }
async fetch() { const alarmTime = await this.storage.get("alarmTime"); console.log("alarmTime",alarmTime) if (!alarmTime) { await this.scheduleAlarm(); } else { return new Response("Water alarm is already scheduled."); } return new Response("Water schedule Successfully!"); }
async alarm() { console.log("Water Alarm Doing"); await this.scheduleAlarm(); }
async scheduleAlarm() { let scheduledTime: number = Date.now() + this.doEverySeconds * 1000; await this.storage.put("alarmTime", scheduledTime.toString()); this.storage.setAlarm(scheduledTime); } }
constructor(state: DurableObjectState, env: Env) { this.storage = state.storage; this.id = state.id; this.doEverySeconds = 2; this.env = env; }
async fetch() { const alarmTime = await this.storage.get("alarmTime"); console.log("alarmTime",alarmTime) if (!alarmTime) { await this.scheduleAlarm(); } else { return new Response("Water alarm is already scheduled."); } return new Response("Water schedule Successfully!"); }
async alarm() { console.log("Water Alarm Doing"); await this.scheduleAlarm(); }
async scheduleAlarm() { let scheduledTime: number = Date.now() + this.doEverySeconds * 1000; await this.storage.put("alarmTime", scheduledTime.toString()); this.storage.setAlarm(scheduledTime); } }
Ah Ok, I get your point, basically what you want to do is execute your alarm call once in 2 seconds, regardless of how many requests you receive within the 2 seconds range, right ?
yes, exactly
ok, let me send you the code
for exmaple alaram calling
First time call = schudle call every 2 second (working fine)
second time call = 2 time schudle call every 2 second
third time call = 3 time schudle call every 2 second
but i want to do
-------------------------------------
First time call = schudle call every 2 second (working fine)
second time call = 1 time schudle call every 2 second
third time call = 1 time schudle call every 2 second
export class Water {
id: string | DurableObjectId;
storage: DurableObjectStorage;
doEverySeconds: number;
env: Env;
constructor(state: DurableObjectState, env: Env) { this.storage = state.storage; this.id = state.id; this.doEverySeconds = 2; this.env = env; }
async fetch() { const alarmTime = await this.storage.get("alarmTime"); console.log("alarmTime",alarmTime) if (!alarmTime) { await this.scheduleAlarm(); } else { return new Response("Water alarm is already scheduled."); } return new Response("Water schedule Successfully!"); }
async alarm() { console.log("Water Alarm Doing"); await this.storage.delete("alarmTime"); }
async scheduleAlarm() { let scheduledTime: number = Date.now() + this.doEverySeconds * 1000; await this.storage.put("alarmTime", scheduledTime.toString()); this.storage.setAlarm(scheduledTime); } } Just replaced the this.scheduleAlarm in the alarm function to await storage.delete
constructor(state: DurableObjectState, env: Env) { this.storage = state.storage; this.id = state.id; this.doEverySeconds = 2; this.env = env; }
async fetch() { const alarmTime = await this.storage.get("alarmTime"); console.log("alarmTime",alarmTime) if (!alarmTime) { await this.scheduleAlarm(); } else { return new Response("Water alarm is already scheduled."); } return new Response("Water schedule Successfully!"); }
async alarm() { console.log("Water Alarm Doing"); await this.storage.delete("alarmTime"); }
async scheduleAlarm() { let scheduledTime: number = Date.now() + this.doEverySeconds * 1000; await this.storage.put("alarmTime", scheduledTime.toString()); this.storage.setAlarm(scheduledTime); } } Just replaced the this.scheduleAlarm in the alarm function to await storage.delete
when i call the API, so alaram calling is only one time
not every 2 secondse
This will be the outcome:
Call to DO at t + 1s: Will schedule the alarm
Call to DO at t + 1.5s: Will return alarm already scheduled (therefore would do nothing)
Call to DO at t + 2s: WIll return alarm already scheduled (therefore would do nothing)
At t + 3s: The alarm will be executed
At t + 5s: Nothing will happen, until the DO schedules the alarm again through the fetch
Is this what you are trying to build ?
Based on what I have provided, do you want the alarm to be executed still at t + 5s, t + 7s, .... t + 99s ?
yes, like this
Can you send the code where you call your DO from the worker ?
When you get the id and then send the fetch request to the DO
but I want to when re-calling the schedule so before, schedule is clear(restart) and then the alarm calling
Ok, can you express it in a timeline like I did here
From t + 1s, to t + 9s
main.ts
--------------------------
import { ThrowableRouter } from 'itty-router-extras';
import { Env } from '../types';
import { withDurables } from 'itty-durable';
export { Water } from './crons/water';
const router = ThrowableRouter();
router.all("", withDurables());
router.get('/water', async (request: Request, env: Env) => {
const doId = env.WATER.newUniqueId();
const WaterInstance = env.WATER.get(doId);
return WaterInstance.fetch(request, env);
});
router.all("", ()=> { return new Response("Route not Found!") });
export default {
fetch: router.handle,
};
crons/water/index.ts
---------------------------------
export class Water {
id: string | DurableObjectId;
storage: DurableObjectStorage;
doEverySeconds: number;
env: Env;
constructor(state: DurableObjectState, env: Env) {
this.storage = state.storage;
this.id = state.id;
this.doEverySeconds = 2;
this.env = env;
}
async fetch() {
const alarmTime = await this.storage.get("alarmTime");
console.log("alarmTime",alarmTime)
if (!alarmTime) {
await this.scheduleAlarm();
} else {
return new Response("Water alarm is already scheduled.");
}
return new Response("Water schedule Successfully!");
}
async alarm() {
console.log("Water Alarm Doing");
await this.storage.delete("alarmTime");
}
async scheduleAlarm() {
let scheduledTime: number = Date.now() + this.doEverySeconds * 1000;
await this.storage.put("alarmTime", scheduledTime.toString());
this.storage.setAlarm(scheduledTime);
}
}
for example:-
first-time call schedule: alarm calling
2s: alarm calling
4s: alarm calling
6s: alarm calling
when I recall the API, it is already scheduled already doing
8s: alarm calling
10s: alarm calling
continue
OR
first time call schudle: alarm calling
2s: alarm calling
4s: alarm calling
6s: alarm calling
Ok, I get it
So, here the new code
1. const doId = env.WATER.newUniqueId(); must be replaced with env.WATER.idFromName('water_instance'). The reason is that you have different DO instance per call if you use newUniqueId(). Different instances means, different storage, they are not synced together ....
2. async alarm() {
console.log("Water Alarm Doing");
await this.scheduleAlarm();
}
he said, water schdule already working so how may i stop and again run?
Ok, if you want to manage the state of your waterfall, here is a better solution
yes, let me know
@Harshil Bodara
Thank you, @omar , It was a very exciting good solution
now schedule is working fine
You are welcome
You should still add more control in case your alarm did stop - For example, on run, if the alarm did not execute since 60minutes, then just rerun it instead of returning already scheduled
Thank you So much! @omar
yes, i got it