不要怂,就是干,撸起袖子干!

You need to sign in or sign up before continuing.
Commit 95104b63 by Sushant Committed by GitHub

feat: support cls-hooked / tests (#11584)

1 parent 766cfa46
...@@ -35,7 +35,11 @@ ...@@ -35,7 +35,11 @@
} }
], ],
"semi": ["error", "always"], "semi": ["error", "always"],
"space-before-function-paren": ["error", "never"], "space-before-function-paren": ["error", {
"named": "never",
"anonymous": "never",
"asyncArrow": "always"
}],
"space-before-blocks": "error", "space-before-blocks": "error",
"space-infix-ops": "error", "space-infix-ops": "error",
"no-multi-spaces": "error", "no-multi-spaces": "error",
...@@ -94,7 +98,7 @@ ...@@ -94,7 +98,7 @@
"no-case-declarations": "off" "no-case-declarations": "off"
}, },
"parserOptions": { "parserOptions": {
"ecmaVersion": 6, "ecmaVersion": 2018,
"sourceType": "script" "sourceType": "script"
}, },
"plugins": ["mocha", "jsdoc"], "plugins": ["mocha", "jsdoc"],
......
...@@ -15,7 +15,6 @@ Notice how the callback passed to `transaction` returns a promise chain, and doe ...@@ -15,7 +15,6 @@ Notice how the callback passed to `transaction` returns a promise chain, and doe
```js ```js
return sequelize.transaction(t => { return sequelize.transaction(t => {
// chain all your queries here. make sure you return them. // chain all your queries here. make sure you return them.
return User.create({ return User.create({
firstName: 'Abraham', firstName: 'Abraham',
...@@ -54,10 +53,10 @@ return sequelize.transaction(t => { ...@@ -54,10 +53,10 @@ return sequelize.transaction(t => {
### Automatically pass transactions to all queries ### Automatically pass transactions to all queries
In the examples above, the transaction is still manually passed, by passing `{ transaction: t }` as the second argument. To automatically pass the transaction to all queries you must install the [continuation local storage](https://github.com/othiym23/node-continuation-local-storage) (CLS) module and instantiate a namespace in your own code: In the examples above, the transaction is still manually passed, by passing `{ transaction: t }` as the second argument. To automatically pass the transaction to all queries you must install the [cls-hooked](https://github.com/Jeff-Lewis/cls-hooked) (CLS) module and instantiate a namespace in your own code:
```js ```js
const cls = require('continuation-local-storage'); const cls = require('cls-hooked');
const namespace = cls.createNamespace('my-very-own-namespace'); const namespace = cls.createNamespace('my-very-own-namespace');
``` ```
...@@ -93,10 +92,6 @@ sequelize.transaction((t1) => { ...@@ -93,10 +92,6 @@ sequelize.transaction((t1) => {
}); });
``` ```
After you've used `Sequelize.useCLS()` all promises returned from sequelize will be patched to maintain CLS context. CLS is a complicated subject - more details in the docs for [cls-bluebird](https://www.npmjs.com/package/cls-bluebird), the patch used to make bluebird promises work with CLS.
**Note:** _[CLS only supports async/await, at the moment, when using cls-hooked package](https://github.com/othiym23/node-continuation-local-storage/issues/98#issuecomment-323503807). Although, [cls-hooked](https://github.com/Jeff-Lewis/cls-hooked/blob/master/README.md) relies on *experimental API* [async_hooks](https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md)_
## Concurrent/Partial transactions ## Concurrent/Partial transactions
You can have concurrent transactions within a sequence of queries or have some of them excluded from any transactions. Use the `{transaction: }` option to control which transaction a query belong to: You can have concurrent transactions within a sequence of queries or have some of them excluded from any transactions. Use the `{transaction: }` option to control which transaction a query belong to:
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
const url = require('url'); const url = require('url');
const path = require('path'); const path = require('path');
const retry = require('retry-as-promised'); const retry = require('retry-as-promised');
const clsBluebird = require('cls-bluebird');
const _ = require('lodash'); const _ = require('lodash');
const Utils = require('./utils'); const Utils = require('./utils');
...@@ -1050,7 +1049,7 @@ class Sequelize { ...@@ -1050,7 +1049,7 @@ class Sequelize {
/** /**
* Start a transaction. When using transactions, you should pass the transaction in the options argument in order for the query to happen under that transaction @see {@link Transaction} * Start a transaction. When using transactions, you should pass the transaction in the options argument in order for the query to happen under that transaction @see {@link Transaction}
* *
* If you have [CLS](https://github.com/othiym23/node-continuation-local-storage) enabled, the transaction will automatically be passed to any query that runs within the callback * If you have [CLS](https://github.com/Jeff-Lewis/cls-hooked) enabled, the transaction will automatically be passed to any query that runs within the callback
* *
* @example * @example
* sequelize.transaction().then(transaction => { * sequelize.transaction().then(transaction => {
...@@ -1074,10 +1073,10 @@ class Sequelize { ...@@ -1074,10 +1073,10 @@ class Sequelize {
* *
* @example <caption>To enable CLS, add it do your project, create a namespace and set it on the sequelize constructor:</caption> * @example <caption>To enable CLS, add it do your project, create a namespace and set it on the sequelize constructor:</caption>
* *
* const cls = require('continuation-local-storage'); * const cls = require('cls-hooked');
* const ns = cls.createNamespace('....'); * const namespace = cls.createNamespace('....');
* const Sequelize = require('sequelize'); * const Sequelize = require('sequelize');
* Sequelize.useCLS(ns); * Sequelize.useCLS(namespace);
* *
* // Note, that CLS is enabled for all sequelize instances, and all instances will share the same namespace * // Note, that CLS is enabled for all sequelize instances, and all instances will share the same namespace
* *
...@@ -1130,8 +1129,9 @@ class Sequelize { ...@@ -1130,8 +1129,9 @@ class Sequelize {
// save namespace as `Sequelize._cls` // save namespace as `Sequelize._cls`
this._cls = ns; this._cls = ns;
// patch bluebird to bind all promise callbacks to CLS namespace Promise.config({
clsBluebird(ns, Promise); asyncHooks: true
});
// return Sequelize for chaining // return Sequelize for chaining
return this; return this;
......
...@@ -29,8 +29,7 @@ ...@@ -29,8 +29,7 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bluebird": "^3.5.0", "bluebird": "^3.7.1",
"cls-bluebird": "^2.1.0",
"debug": "^4.1.1", "debug": "^4.1.1",
"dottie": "^2.0.0", "dottie": "^2.0.0",
"inflection": "1.12.0", "inflection": "1.12.0",
...@@ -56,7 +55,7 @@ ...@@ -56,7 +55,7 @@
"chai-as-promised": "^7.x", "chai-as-promised": "^7.x",
"chai-datetime": "^1.x", "chai-datetime": "^1.x",
"chai-spies": "^1.x", "chai-spies": "^1.x",
"continuation-local-storage": "^3.x", "cls-hooked": "^4.2.2",
"cross-env": "^5.2.1", "cross-env": "^5.2.1",
"env-cmd": "^8.0.2", "env-cmd": "^8.0.2",
"esdoc": "^1.1.0", "esdoc": "^1.1.0",
......
...@@ -5,26 +5,24 @@ const chai = require('chai'), ...@@ -5,26 +5,24 @@ const chai = require('chai'),
Support = require('./support'), Support = require('./support'),
Sequelize = Support.Sequelize, Sequelize = Support.Sequelize,
Promise = Sequelize.Promise, Promise = Sequelize.Promise,
cls = require('continuation-local-storage'), cls = require('cls-hooked'),
current = Support.sequelize; current = Support.sequelize;
if (current.dialect.supports.transactions) { if (current.dialect.supports.transactions) {
describe(Support.getTestDialectTeaser('Continuation local storage'), () => { describe(Support.getTestDialectTeaser('CLS (Async hooks)'), () => {
before(function() { before(() => {
this.thenOriginal = Promise.prototype.then; current.constructor.useCLS(cls.createNamespace('sequelize'));
Sequelize.useCLS(cls.createNamespace('sequelize'));
}); });
after(() => { after(() => {
cls.destroyNamespace('sequelize');
delete Sequelize._cls; delete Sequelize._cls;
}); });
beforeEach(function() { beforeEach(function() {
return Support.prepareTransactionTest(this.sequelize).then(sequelize => { return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
this.sequelize = sequelize; this.sequelize = sequelize;
this.ns = cls.getNamespace('sequelize'); this.ns = cls.getNamespace('sequelize');
this.User = this.sequelize.define('user', { this.User = this.sequelize.define('user', {
name: Sequelize.STRING name: Sequelize.STRING
}); });
...@@ -36,7 +34,7 @@ if (current.dialect.supports.transactions) { ...@@ -36,7 +34,7 @@ if (current.dialect.supports.transactions) {
it('does not use continuation storage on manually managed transactions', function() { it('does not use continuation storage on manually managed transactions', function() {
return Sequelize._clsRun(() => { return Sequelize._clsRun(() => {
return this.sequelize.transaction().then(transaction => { return this.sequelize.transaction().then(transaction => {
expect(this.ns.get('transaction')).to.be.undefined; expect(this.ns.get('transaction')).not.to.be.ok;
return transaction.rollback(); return transaction.rollback();
}); });
}); });
...@@ -143,12 +141,14 @@ if (current.dialect.supports.transactions) { ...@@ -143,12 +141,14 @@ if (current.dialect.supports.transactions) {
}); });
}); });
}); });
});
it('bluebird patch is applied', function() { it('automagically uses the transaction in all calls with async/await', function() {
expect(Promise.prototype.then).to.be.a('function'); return this.sequelize.transaction(async () => {
expect(this.thenOriginal).to.be.a('function'); await this.User.create({ name: 'bob' });
expect(Promise.prototype.then).not.to.equal(this.thenOriginal); await expect(this.User.findAll({ transaction: null })).to.eventually.have.length(0);
await expect(this.User.findAll({})).to.eventually.have.length(1);
});
});
}); });
it('CLS namespace is stored in Sequelize._cls', function() { it('CLS namespace is stored in Sequelize._cls', function() {
......
...@@ -4,19 +4,18 @@ const chai = require('chai'), ...@@ -4,19 +4,18 @@ const chai = require('chai'),
expect = chai.expect, expect = chai.expect,
Support = require('../support'), Support = require('../support'),
current = Support.sequelize, current = Support.sequelize,
cls = require('continuation-local-storage'), cls = require('cls-hooked'),
sinon = require('sinon'), sinon = require('sinon'),
stub = sinon.stub; stub = sinon.stub;
describe(Support.getTestDialectTeaser('Model'), () => { describe(Support.getTestDialectTeaser('Model'), () => {
describe('method findOrCreate', () => { describe('method findOrCreate', () => {
before(() => { before(() => {
current.constructor.useCLS(cls.createNamespace('sequelize')); current.constructor.useCLS(cls.createNamespace('sequelize'));
}); });
after(() => { after(() => {
cls.destroyNamespace('sequelize');
delete current.constructor._cls; delete current.constructor._cls;
}); });
...@@ -36,7 +35,6 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -36,7 +35,6 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}); });
it('should use transaction from cls if available', function() { it('should use transaction from cls if available', function() {
const options = { const options = {
where: { where: {
name: 'John' name: 'John'
...@@ -54,7 +52,6 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -54,7 +52,6 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}); });
it('should not use transaction from cls if provided as argument', function() { it('should not use transaction from cls if provided as argument', function() {
const options = { const options = {
where: { where: {
name: 'John' name: 'John'
......
...@@ -1336,15 +1336,15 @@ export class Sequelize extends Hooks { ...@@ -1336,15 +1336,15 @@ export class Sequelize extends Hooks {
* }); * });
* ``` * ```
* *
* If you have [CLS](https://github.com/othiym23/node-continuation-local-storage) enabled, the transaction * If you have [CLS](https://github.com/Jeff-Lewis/cls-hooked) enabled, the transaction
* will automatically be passed to any query that runs witin the callback. To enable CLS, add it do your * will automatically be passed to any query that runs witin the callback. To enable CLS, add it do your
* project, create a namespace and set it on the sequelize constructor: * project, create a namespace and set it on the sequelize constructor:
* *
* ```js * ```js
* const cls = require('continuation-local-storage'), * const cls = require('cls-hooked');
* ns = cls.createNamespace('....'); * const namespace = cls.createNamespace('....');
* const Sequelize = require('sequelize'); * const Sequelize = require('sequelize');
* Sequelize.cls = ns; * Sequelize.useCLS(namespace);
* ``` * ```
* Note, that CLS is enabled for all sequelize instances, and all instances will share the same namespace * Note, that CLS is enabled for all sequelize instances, and all instances will share the same namespace
* *
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!