Cannot use importScripts() inside Workers


#1

Hi,

I have been trying to track exceptions happening inside Workers using Sentry.

In my worker script, I try to do the following:

self.importScripts('https://cdn.ravenjs.com/3.19.1/raven.min.js'); 
Raven.config('sentryPublicKey').install();

self.addEventListener("fetch", event => { 
event.respondWith(handle(event)); 
});

async function handle(event) { 
let request = event.request; 
try { 
// do something; 
} 
catch (err) { 
Raven.captureException(err); 
} 
}

However, I am unable to use importScripts() inside Workers.

The Dashboard throws me the following error on trying to save my Workers script:

“Uncaught TypeError: self.importScripts is not a function at line 1”

Can someone guide me a bit on how can I track exceptions generated by Cloudflare Workers using Sentry?


#2

On doing, console.log(‘self’, self);

I noticed that the self object is of type “ServiceWorkerGlobalScope”

whereas the method importScripts() is available for “WorkerGlobalScope” objects. [1]

“ServiceWorkerGlobalScope” does not seem to have an importScripts() method. [2]

[1] https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/importScripts
[2] https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope


#3

Hi @khan.sana,

As luck would have it, Cloudflare’s very own @zproser just published a blog post which shows how to do exactly what you’re attempting. You could probably use his script as a template for your own.

To more fully answer your question: we don’t currently support the importScripts() function. Supporting it would significantly complicate script security auditing, and could be a source of nondeterminism if the script fetched by importScripts() is not pinned to a specific version. But, if scripts imported by importScripts() are pinned to a specific version, then using a tool like webpack, rollup, or browserify to bundle your dependencies with the main worker script is a better option, as this ensures that script cold starts take much less time – this is important because when scripts are cold started there is already a client request waiting for it.

However, for the specific use case of logging to Sentry, I don’t recommend bundling RavenJS with a tool like webpack. The problem, which @zproser mentions in the blog post, is that RavenJS.captureException() uses a fetch() call under the hood to report the error to Sentry, but there is no way to access the promise returned by that fetch(). Without that promise, there is no way for the Cloudflare Workers runtime to know that it should wait for that outstanding Sentry request to complete before considering the overall FetchEvent lifetime complete. Instead, it assumes that as soon as the worker has finished sending the main Response back to the client, the FetchEvent lifetime is complete, and all outstanding asynchronous tasks (such as the Sentry request) are canceled. Since the code path which calls RavenJS.captureException() fulfills that main Response with undefined, the Sentry request is bound to be immediately canceled before it goes anywhere, and you won’t see your Sentry logs.

The solution is to use event.waitUntil(promise) to instruct the Workers runtime to wait for the Sentry request to complete before tearing down the FetchEvent. See the blog post linked above for details. :slight_smile:

Harris


#4

Thanks @harris. That was helpful.

I am now using the template script to log all exceptions to Sentry :slight_smile:

Regards,
Sana