-
-
Notifications
You must be signed in to change notification settings - Fork 624
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
fix: circular dependencies #3081
fix: circular dependencies #3081
Conversation
pool.js and pool_connection.js required index.js, and index.js required pool.js and pool_connection.js. Circular dependency can cause all sorts of problems. This fix aims to provide a step towards fixing a problem with @opentelemetry/instrumentation-mysql2, which looses several exports when using its patched require. For instance, `format` is lost and can cause an instrumented application to crash.
index.js and promise.js require each other. Circular dependency can cause all sorts of problems. This commit aims to fix a problem with @opentelemetry/instrumentation-mysql2, which looses several exports when using its patched require. For instance, `format` is lost and can cause an instrumented application to crash.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3081 +/- ##
==========================================
+ Coverage 88.13% 88.23% +0.10%
==========================================
Files 71 83 +12
Lines 12890 12983 +93
Branches 1355 1370 +15
==========================================
+ Hits 11361 11456 +95
+ Misses 1529 1527 -2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Thanks, @tpraxl 🚀 I remember experiencing an error with Just a small recommendation, moving from |
@wellwelwel You have a point there. In that case however, it feels weird to arbitrarily stuff some exported functions together in lib/common.js . It made sense when we were talking about commons for index.js and promise.js, but in lib, I would split common.js up into the following files and get rid of common.js
I'm working on it and will push the result |
The proposal to put common.js into lib was good, but it felt weird to arbitrarily stuff just some exported functions in lib/common.js. This made sense when common.js was meant to provide commons for index.js and promise.js. But in the lib, this felt like a weird scope. I therefore split common.js into - lib/create_connection.js - lib/create_pool.js - lib/create_pool_cluster.js Also made `require` more consistent in all affected files: all `require` files now have a js suffix when they refer to a single local file.
Hey @tpraxl, I tested your changes with
import mysql from 'mysql2/promise';
mysql.createPool({});
import { defineConfig } from 'rollup';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
export default defineConfig({
input: 'index.js',
output: {
file: 'dist.js',
},
plugins: [nodeResolve(), commonjs(), json()],
});
{
"type": "module",
"devDependencies": {
"@rollup/plugin-commonjs": "^28.0.0",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"rollup": "^4.24.0"
},
"dependencies": {
"mysql2": "file:../node-mysql2"
}
} I'll try to investigate this further. |
promise.js was required by lib sources, and promise.js required the same lib sources eventually. Extracted the respective classes to lib. Also extracted functions that are shared between several of the new files. Decided to put each exported class / function into its own file. This may bloat the lib folder a bit, but it provides clarity (where to find what).
Thanks for your finding. No need to investigate further IMHO, I would propose to extract See https://github.com/tpraxl/node-mysql2/pull/1/files If these changes are OK for you, I'll merge them into fix/circular-dependencies and update this PR. |
@wellwelwel are you fine with my changes? |
I am facing the same opentelemetry issue and i verified that this MR fixes it. Please merge this MR. |
@tpraxl, sorry for the delay (I've been away for a few days). Testing in the new branch, I'm facing this now:
|
@mknj, these refactors involve some critical files and modules, so it's ideal to review them carefully 🙋🏻♂️ Please, feel free to contribute to the review 🤝 |
I'll investigate this further, just haven't had the time yet. Before, I only fixed the obvious circular dependencies until it was working for the instrumentation. Now, I'll use I fear, at a quick first glance, that this fix won't be possible without breaking changes. But give me some time to investigate. |
Thanks, @tpraxl 🤝 I'll try to play in your last changes too 🙋🏻♂️ |
@tpraxl, I didn't expect it to be so complex. As the warning from Rollup doesn't crashes or block the compilation, I'm fine with the current stage of this PR.
Then, when #2803 moves on or a major release milestone comes out, we can discuss it with more flexibility. |
The extraction of classes was performed without extracting the patch of methods like `escape`, etc. The patching is now performed in the files that define the respective classes, guaranteeing patched versions when these files are required.
I am struggling, because madge shows that in this branch, I actually increased the amount of circular dependencies when I untangled index.js / promise.js (because there are more files now). The only version having less circular dependencies is https://github.com/tpraxl/node-mysql2/tree/fix/circular-dependencies-promise However, more problems are popping up when you go down the rabbit hole. See https://github.com/tpraxl/test-esm-mysql-otel/blob/main/README.md for a thorough description and a way to reproduce the problems. Basically, with the new version, @opentelemetry will not activate instrumentation for mysql2 anymore, because it does not encounter the main module when used with esm. This would be only possible with a workaround, that I also provided in https://github.com/tpraxl/node-mysql2/tree/fix/open-telemetry-not-activated So, if we merge this PR now, instrumentation for esm will not crash anymore, it will simply be gone for esm users. Sigh. I hope, I'll find some time to investigate the new issues and maybe I can find a way to trigger a fix. |
My proposal after having thought about it again: Let's merge https://github.com/tpraxl/node-mysql2/tree/fix/circular-dependencies-promise into this PR. Live with the fact that instrumentation is still not working for the callback variant in esm scenarios. At least, it does not crash anymore when instrumented. Next steps:
What do you think? |
I didn't get to review tpraxl#1 (I just did a quick compilation test).
@tpraxl, feel free to proceed 🙋🏻♂️ |
Merged fix/circular-dependencies-promise into this branch. Summary: |
@tpraxl, I'll ask for a few days to review it carefully. Thanks in advance 🤝 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i feel like a linter
@mknj thanks for your findings. You are even better than |
Co-authored-by: mknj <github@mknj.de>
Good news: I adjusted the test repo and added the fixed start commands: Also adjusted the README to document this issue. So, with the fixed startup, we actually gain instrumentation for the callback mode as well and with this PR merged, the format function will be available as well. |
@tpraxl, can I make some minor adjustments directly to your branch? ☔️ Just a note on coverage: the lines that aren't covered aren't new, they've just been moved to other files, triggering the missing coverage. |
Of course, feel free. |
Hey @tpraxl, I think I have a good news too:
|
These are the remaining circular imports:
To fix it in a simple way, I just moved the original classes for each conflict to a new file, removing the For example:
'use strict';
const BaseConnection = require('./base_connection.js');
class Connection extends BaseConnection {
promise(promiseImpl) {
const PromiseConnection = require('./promise_connection.js');
return new PromiseConnection(this, promiseImpl);
}
}
module.exports = Connection;
// ...
if (
typeof BaseConnection.prototype[func] === 'function' && // ⬅️
PromiseConnection.prototype[func] === undefined
) {
PromiseConnection.prototype[func] = (function factory(funcName) {
return function () {
return BaseConnection.prototype[funcName].apply( // ⬅️
this.connection,
arguments,
);
};
})(func);
}
}
// ...
|
After almost 3 months, finally, I believe it's ready to merge 🚀 Not for this PR (which is already long enough), but I believe it's worth adding an E2E test (similar to the one I carried out with Rollup) to ensure that after all our efforts, this conflict doesn't occur again. |
It's already available in the 3.11.5-canary.d5a76e6c version 🎉 As said in #3207, although no logic has actually been changed, as it's a relatively large refactoring of critical files, I intend to keep the canary version for at least a week before merging it to an official release. |
This commit addresses circular dependencies between index.js and promise.js, as well as within files in the lib directory such as pool.js and pool_connection.js.
It introduces a new common.js module to centralize shared functionalities, thus breaking the direct dependencies among these files.
This approach resolves issues with the @opentelemetry/instrumentation-mysql2 package, which was losing several exports due to the circular dependencies.
You can reproduce the problem with this simple test repo:
https://github.com/tpraxl/test-esm-mysql-otel
Follow the instructions in the README.md to see the respective warnings.
To verify that this PR fixes the issue, check it out, run
npm i && npm pack
and install the fixed version into the test repo usingnpm i $PATH_TO_MYSQL2/mysql2-3.11.3.tgz
. Runnpm start
again in the checked out test repo to see the warnings vanish.This PR would fix open-telemetry/opentelemetry-js-contrib#1511