if this happens in the codebase and someone forget to explicitly try-catch it, there is afaik zero w
if this happens in the codebase and someone forget to explicitly try-catch it, there is afaik zero way to observe or react to that
A Tail Worker receives information about the execution of other Workers (known as producer Workers), such as HTTP statuses, data passed to console.log() or uncaught exceptions
tail handler and in the wrangler.json/wrangler.toml, point the Worker to itself.addEventListener('uncaughtexception', ...) like node doesRegarding the behavior of setting an alarm and throwing right after, I will check with the team and get back to you.
deleteAll(), you can reference the same ID and get it running again.[ERROR] TypeError: Cannot read properties of undefined (reading 'MY_BUCKET'). I can do R2 operations in the hono routes but not within the DO at the moment using the bindingsenv you get in the DO constructor has nothing to do with the Hono env. In your code it should be the Bindings directly. So doing await this.env.MY_BUCKET.put(...) will probably work.that they should be architecting their app for autocleanup/storing IDs somewhereI still don't agree with this. Autocleaning are very different things from storing IDs.
export class MyDurableObject {
constructor(state, env) {
this.state = state;
this.env = env;
}
async alarm() {
console.log("Alarm triggered");
// Will this alarm be set? or would it be "overriden" by the retry of the original alarm
await this.state.storage.setAlarm(Date.now() + 150000);
// Call a method that fails
await this.failingMethod(); // failure
}
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === "/start") {
console.log("Starting recursive alarm loop...");
await this.state.storage.setAlarm(Date.now() + 5000);
return new Response("Alarm scheduled.");
}
return new Response("Unknown command", { status: 400 });
}
async failingMethod() {
throw new Error("Intentional failure to demonstrate failure handling");
}
}try {
//
} catch (error) {
console.error(
"x QUEUE ERROR",
`Error processing step ${currentStep} for ${x}:`,
error
);
sentry.captureException(error);
const currentRetries = this.stepRetries[currentStep] || 0;
const retryDelays = [
1 * 60 * 1000, // 1 minute
10 * 60 * 1000, // 10 minutes
60 * 60 * 1000, // 1 hour
4 * 60 * 60 * 1000, // 4 hours
24 * 60 * 60 * 1000, // 24 hours
];
if (currentRetries < retryDelays.length) {
this.stepRetries[currentStep] = currentRetries + 1;
const delay = retryDelays[currentRetries];
this.setAlarm(Date.now() + delay);
console.log(
`Retrying step ${currentStep} (attempt #${
this.stepRetries[currentStep]
}) for ${x} in ${delay / 1000 / 60} minutes`
);
} else {
console.error(
"x SKIPPING STEP",
`Step ${currentStep} failed ${retryDelays.length} times, skipping and moving to next step`
);
this.stepRetries[currentStep] = 0;
this.step = currentStep + 1;
this.setAlarm(Date.now());
}
await this.persist();
}type Bindings = {
MY_BUCKET: R2Bucket
MY_DO: DurableObjectNamespace<MyDurableObject>
}
type Variables = {}
export type Env = {
Bindings: Bindings
Variables: Variables
}export class MyDurableObject extends DurableObject<Env> {
storage: DurableObjectStorage
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env)
this.storage = ctx.storage
console.log('DO constructor', this.env)
}
async test() {
const upload = await this.env.Bindings.MY_BUCKET.put(`test`, 'test')
return upload
}
}// do imported above
const id = c.env.MY_DO.idFromName('my-durable-object')
const durableObject = c.env.MY_DO.get(id)
const zipFile = await durableObject.test()
return c.json({ message: 'Test', zipFile })
export {MY_DO}DO constructor {
MY_DO: DurableObjectNamespace {},
MY_BUCKET: R2Bucket {},
}
✘ [ERROR] TypeError: Cannot read properties of undefined (reading 'MY_BUCKET')