Skip to content

feat(cloudflare): Split alarms into multiple traces and link them#19373

Open
JPeer264 wants to merge 1 commit intodevelopfrom
jp/split-alarm
Open

feat(cloudflare): Split alarms into multiple traces and link them#19373
JPeer264 wants to merge 1 commit intodevelopfrom
jp/split-alarm

Conversation

@JPeer264
Copy link
Member

@JPeer264 JPeer264 commented Feb 18, 2026

closes #19105
closes JS-1604

closes #19453
closes JS-1774

This actually splits up alarms into its own traces and binding them with span links. It also adds the setAlarm, getAlarm and deleteAlarm instrumentation, which is needed to make this work.

The logic works as following. When setAlarm is getting called it will store the alarm inside the durable object. Once the alarm is being executed the previous trace link will be retrieved via ctx.storage.get and then set as span link. Using the durable object itself as storage between alarms is even used on Cloudflare's alarm page.

Also it is worth to mention that only 1 alarm at a time can happen, so it is safe to use a fixed key for the previous trace. I implemented the trace links, so they could be reused in the future for other methods as well, so they are not exclusively for alarms.

@JPeer264 JPeer264 self-assigned this Feb 18, 2026
@JPeer264 JPeer264 changed the title ref(cloudflare): Move internal files and functions around feat(cloudflare): Split alarms into multiple traces and link them Feb 18, 2026
@linear
Copy link

linear bot commented Feb 18, 2026

@github-actions
Copy link
Contributor

github-actions bot commented Feb 18, 2026

Codecov Results 📊


Generated by Codecov Action

@github-actions
Copy link
Contributor

github-actions bot commented Feb 18, 2026

size-limit report 📦

Path Size % Change Change
@sentry/browser 25.61 kB - -
@sentry/browser - with treeshaking flags 24.12 kB - -
@sentry/browser (incl. Tracing) 42.42 kB - -
@sentry/browser (incl. Tracing, Profiling) 47.08 kB - -
@sentry/browser (incl. Tracing, Replay) 81.24 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 70.86 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 85.93 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 98.09 kB - -
@sentry/browser (incl. Feedback) 42.33 kB - -
@sentry/browser (incl. sendFeedback) 30.28 kB - -
@sentry/browser (incl. FeedbackAsync) 35.28 kB - -
@sentry/browser (incl. Metrics) 26.78 kB - -
@sentry/browser (incl. Logs) 26.92 kB - -
@sentry/browser (incl. Metrics & Logs) 27.6 kB - -
@sentry/react 27.37 kB - -
@sentry/react (incl. Tracing) 44.76 kB - -
@sentry/vue 30.06 kB - -
@sentry/vue (incl. Tracing) 44.26 kB - -
@sentry/svelte 25.64 kB - -
CDN Bundle 28.16 kB - -
CDN Bundle (incl. Tracing) 43.25 kB - -
CDN Bundle (incl. Logs, Metrics) 29 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 44.09 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 68.08 kB - -
CDN Bundle (incl. Tracing, Replay) 80.12 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 80.99 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 85.56 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 86.46 kB - -
CDN Bundle - uncompressed 82.33 kB - -
CDN Bundle (incl. Tracing) - uncompressed 128.05 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 85.17 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 130.88 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 208.83 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 244.93 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 247.75 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 257.73 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 260.54 kB - -
@sentry/nextjs (client) 47.17 kB - -
@sentry/sveltekit (client) 42.88 kB - -
@sentry/node-core 52.18 kB +0.02% +8 B 🔺
@sentry/node 166.54 kB +0.01% +6 B 🔺
@sentry/node - without tracing 93.97 kB +0.01% +9 B 🔺
@sentry/aws-serverless 109.47 kB +0.01% +6 B 🔺

View base workflow run

Base automatically changed from jp/prepare-context-instrument to develop February 18, 2026 10:53
@JPeer264 JPeer264 marked this pull request as ready for review February 20, 2026 10:59
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

const attributes = {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: wrapperOptions.spanOp || 'function',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.durable_object',
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default spanOp changes behavior for webSocket methods

Medium Severity

The refactoring changed span attribute assignment from conditional (only when spanOp is provided) to unconditional with a default of 'function'. This unintentionally affects webSocketMessage, webSocketClose, and webSocketError in durableobject.ts, which don't pass spanOp. Previously their spans had no sentry.op or sentry.origin attributes; now they get op: 'function' and origin: 'auto.faas.cloudflare.durable_object'. The 'function' op isn't semantically correct for WebSocket event handlers.

Additional Locations (1)

Fix in Cursor Fix in Web

};
await originalStorage.put(getTraceLinkKey(methodName), storedContext);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling in storeSpanContext causes user-visible failures

Medium Severity

storeSpanContext lacks try-catch around the originalStorage.put() call, unlike its counterpart getStoredSpanContext which wraps its read in try-catch. In instrumentDurableObjectStorage, storeSpanContext is called after setAlarm already succeeded. If the internal storage write fails (e.g., quota limit), the error propagates to user code, making a successful setAlarm call appear to fail. The same issue applies to storeContextIfNeeded calls in wrapMethodWithSentry, where a storage failure after a successful alarm handler would cause the alarm to appear to throw.

Additional Locations (1)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cloudflare Instrument Alarm Api Cloudflare alarm split in different traces

1 participant

Comments