Skip to content

feat(browser): Add debugId sync APIs between web worker and main thread #16981

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 17, 2025

Conversation

Lms24
Copy link
Member

@Lms24 Lms24 commented Jul 14, 2025

This PR adds two Browser SDK APIs to let the main thread know about debugIds of worker files:

  • webWorkerIntegration({worker}) to be used in the main thread
  • registerWebWorker(self) to be used in the web worker

The communication between workers and main thread is established between both APIs and they have to be used both for the sync to work correctly. Another limitation around this approach is that users must set up webWorkerInegration before they register their own message listeners. This ensures that the message from registerWebWorker is not propagated to user-created message listeners. We'll document this thoroughly in docs and I already added a section about this in the JSDoc.

Because of the strict co-dependence of both APIs, I decided to add them in one PR (also makes testing easier).

Usage

// main.js
Sentry.init({...})

const worker = new MyWorker(...);

Sentry.addIntegration(Sentry.webWorkerIntegration({ worker }));

worker.addEventListener('message', e => {...});
// worker.js
Sentry.registerWebWorker({ self });

self.postMessage(...);

Multiple Workers

Multiple workers are also supported:

// main.js
Sentry.init({...})

const worker = new MyWorker(...);
const worker2 = new MyWorker2(...);

Sentry.addIntegration(Sentry.webWorkerIntegration({ worker: [worker, worker2] }));

worker.addEventListener('message', e => {...});

A worker can also be passed to the integration after it was initialized. This is helpful if workers are initialized lazily or at different times:

// main.js
Sentry.init({...})

const worker = new MyWorker(...);

const webWorkerIntegration = Sentry.webWorkerIntegration({ worker });

Sentry.addIntegration(webWorkerIntegration);

worker.addEventListener('message', e => {...});

// sometime later

const lazyWorker = new MyLazyWorker(...);
webWorkerIntegration.addWorker(lazyWorker);
lazyWorker.addEventListener('message', e => {...});

I decided to keep both APIs very general around web workers because I think there could be other use cases in which we can sync data by using the worker's message channels. This should be as easy as listening for other messages.

also added

  • unit tests for the two APIs
  • integration test testing the webWorkerIntegration
  • e2e test demonstrating correct usage of both APIs together

closes #16975
closes #16976

@Lms24 Lms24 self-assigned this Jul 14, 2025
@Lms24 Lms24 force-pushed the lms/feat-browser-web-worker-debugIds branch from ef4ba1a to 3acf7a8 Compare July 16, 2025 08:55
@@ -28,7 +28,7 @@ function fixPackageJson(cwd: string): void {

// 2. Fix volta extends
if (!packageJson.volta) {
throw new Error('No volta config found, please provide one!');
throw new Error("No volta config found, please add one to the test app's package.json!");
Copy link
Member Author

Choose a reason for hiding this comment

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

adjusted this message because I didn't realize the volta config needed to be added to the e2e test apps. Might be a me-problem but I think the message is now fool-proof :D

@Lms24 Lms24 marked this pull request as ready for review July 16, 2025 11:00
@Lms24 Lms24 requested review from timfish, mydea, a team and AbhiPrasad and removed request for a team July 16, 2025 11:01
cursor[bot]

This comment was marked as outdated.

Copy link
Collaborator

@timfish timfish left a comment

Choose a reason for hiding this comment

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

LGTM.

What happens if you have more than one worker and try and add them both? If you add the integration twice will it remove the one you added first?

@Lms24
Copy link
Member Author

Lms24 commented Jul 16, 2025

What happens if you have more than one worker and try and add them both? If you add the integration twice will it remove the one you added first?

Good point, thanks for raising! The first installed integration wins and the second instance wouldn't be added (=> setupOnce wouldn't be called and debugIds not added).

I think we have a couple of options:

  1. We can let the integration accept an array of workers instead. This assumes though that all workers are initialized at the same time. Which seems unlikely.
  2. We can add a method on the integration (webWorkerIntegration.addWorker(worker)), similarly to how the replay and feature flag integrations work. This increases complexity of the integration (or rather typing-wise) but still comes with the benefit that everything can be handled within one integration.
  3. We could also move away from making the main thread part an integration at all but just a regular function (e.g. Sentry.instrumentWorker()` or something similar). I wanted to go with the integration because it's a well-known pattern and seemed fitting. But maybe we should revisit.

I'm tentatively tending towards 2 but don't yet have a strong opinion. Any thoughts on this? Will also take it to the team to discuss shortly.

(set the PR to draft in the meantime)

@Lms24 Lms24 marked this pull request as draft July 16, 2025 12:48
@timfish
Copy link
Collaborator

timfish commented Jul 16, 2025

Another possibly more hacky solution is to set a different name for each instance of the Integration:

let count = 0;

export const webWorkerIntegration = defineIntegration(({ worker }: WebWorkerIntegrationOptions) => ({
  name: `${INTEGRATION_NAME}-${count++}`,
  setupOnce: () => {

Since this integration isn't default included users wont need to use the name to filter it out and because the name differs, multiples can be added?

@Lms24
Copy link
Member Author

Lms24 commented Jul 16, 2025

I went with options 1 and 2 combined. Decided to do it "properly" instead of the "hack" (though I liked the suggestion) to avoid the side effect it would introduce and to keep the integration name constant. Not sure why users would look up or remove the integration but let's keep the integration names predictable.

@Lms24 Lms24 marked this pull request as ready for review July 16, 2025 14:09
Copy link
Collaborator

@timfish timfish left a comment

Choose a reason for hiding this comment

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

Looks good!

@Lms24 Lms24 merged commit e8f2b2d into develop Jul 17, 2025
174 checks passed
@Lms24 Lms24 deleted the lms/feat-browser-web-worker-debugIds branch July 17, 2025 07:29
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.

Add worker thread Sentry.registerWorker(self) API Add main thread webWorkerIntegration
3 participants