Dynamsoft / barcode-reader-javascript

Dynamsoft Barcode Reader JavaScript SDK for package managers. PDF417, QR Code, DataMatrix, MaxiCode and more are supported.
https://www.dynamsoft.com/barcode-reader/sdk-javascript/
Other
168 stars 111 forks source link

Library fails with new relic #122

Closed macieklad closed 1 year ago

macieklad commented 1 year ago

Hi, we wanted to start using new relic in our app. We have added the recommended scripts, but the website fails when trying to initialize barcode reader with the following error "license" is not allowed to change after "createInstance" or "loadWasm" is called.

This error happens before the first call to createInstance, so there was no misconfiguration on our side. The scanner worked well without new relic.

I have debugged it as far as I could, and I discovered that in the library code, the isEmpty check returns false, and this throws errors. Then I have removed those checks to validate if the license was really modified and this would fix the problem, but the real case seems to be the underlying logic in the isEmpty property. It checks if the variable task - a promise if I inferred it correct from minified code is not resolved and not empty, an that triggers the error, this may be a problem with instantiating the underlying scanner worker instance.

To reproduce this issue, please try creating worker instance with a basic new relic script added to html page. I cannot share our code as it includes new relic licenses but I can probably show a demo privately.

Keillion commented 1 year ago

macieklad, thanks for your report,

I'm not familiar with new relic. But I will try the platform.

I remember a similar problem I encountered when developing in react18. >>dbrjs react 18 hooks sample

It cause by StrictMode, which will try to do many things twice in developing mode. Problems not happen in production mode.

I did some tricks to bypass this problem, and there is the code, although I can't remember how I did it and which is the key part.

Hope the sample helpful. I will update the issue if I find something new.

Keillion commented 1 year ago

If you need to go online urgently, and it does not cause other problems.

In my experience in react 18, you can simply add try catch before and after setting the license code to ignore this error.

try{
  BarcodeReader.license = 'xxxxxxxxxxxxxxxxxxxxxx';
}catch(_){}
macieklad commented 1 year ago

It unfortunately fails also in production - and this is our main problem, so catching it that way will prevent license from being set anyways. I have tested your suggestion and didn't achieve much. The createInstance promise enters deadlock and is never resolved. Maybe it interrupts some communication with the library? Unfortunately I'm not able to investigate further without an access to the library code ;/

Keillion commented 1 year ago

What dbrjs version you use? You can get the version through file name or console.log(BarcodeReader.version).

In most versions, the behavior should be like this:

Keillion commented 1 year ago

I reproduced this error in new relic.

Keillion commented 1 year ago

new relic wraps Promise, causing problems.

Commit it out.

/*window.Promise = r, */ 

sample: https://github.com/dynamsoft-rd-0/dbrjs-mass-samples/blob/master/new-relic.html#L435


I'm not sure if new relic need to make use of the Promise.

Another way:

self._OriPromise = self.Promise;

Before add new relic.

Then modify dbr.js

{
let Promise = self._OriPromise;
\* dbrjs original code *\
}

Use your modified dbr.js.

You may need to define engineResourcePath, because the modified dbr.js not in the same place as the wasm.

Dynamsoft.DBR.BarcodeReader.engineResourcePath = "https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode@<<<<<version>>>>>/dist/";
macieklad commented 1 year ago

It worked like a charm, thank you! I tried to go the second route to not remove anything from new relic, but the code still hangs so we went with the first route. Do you have any idea how the code would look like for engineResourcePath when we are using webpack and it is bundled in node? I'm closing the issue as we are happy with the first solution, but maybe there could be a way to protect the library in the future from such modifications? (altough I know that manipulating globals is an uncharted territory).

Anyway, thanks for help!

Keillion commented 1 year ago

engineResourcePath will be no different for webpack.

You should always set engineResourcePath when you use js packaging tools. You can see the it in our vue/angular/react sample, because they almost all use webpack.

And the second route is difficult to deal with webpack. You need to modify /node_module/dynamsoft-javascript-barcode/dist/dbr.pure.esm.js. Oh, this must take some talking. And the modification will be gone after npm i.


Then 2 choices leave:

a. Not modify new relic. Include modified dbr.js by <script>. Sample >> b. Modify new relic. You can use webpack and import, enjoy typescript intellisense.


Glad to help you.