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

Commit 95104b63 by Sushant Committed by GitHub

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

1 parent 766cfa46
......@@ -35,7 +35,11 @@
}
],
"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-infix-ops": "error",
"no-multi-spaces": "error",
......@@ -94,7 +98,7 @@
"no-case-declarations": "off"
},
"parserOptions": {
"ecmaVersion": 6,
"ecmaVersion": 2018,
"sourceType": "script"
},
"plugins": ["mocha", "jsdoc"],
......
......@@ -15,7 +15,6 @@ Notice how the callback passed to `transaction` returns a promise chain, and doe
```js
return sequelize.transaction(t => {
// chain all your queries here. make sure you return them.
return User.create({
firstName: 'Abraham',
......@@ -54,10 +53,10 @@ return sequelize.transaction(t => {
### 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
const cls = require('continuation-local-storage');
const cls = require('cls-hooked');
const namespace = cls.createNamespace('my-very-own-namespace');
```
......@@ -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
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 @@
const url = require('url');
const path = require('path');
const retry = require('retry-as-promised');
const clsBluebird = require('cls-bluebird');
const _ = require('lodash');
const Utils = require('./utils');
......@@ -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}
*
* 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
* sequelize.transaction().then(transaction => {
......@@ -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>
*
* const cls = require('continuation-local-storage');
* const ns = cls.createNamespace('....');
* const cls = require('cls-hooked');
* const namespace = cls.createNamespace('....');
* 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
*
......@@ -1130,8 +1129,9 @@ class Sequelize {
// save namespace as `Sequelize._cls`
this._cls = ns;
// patch bluebird to bind all promise callbacks to CLS namespace
clsBluebird(ns, Promise);
Promise.config({
asyncHooks: true
});
// return Sequelize for chaining
return this;
......
......@@ -29,8 +29,7 @@
],
"license": "MIT",
"dependencies": {
"bluebird": "^3.5.0",
"cls-bluebird": "^2.1.0",
"bluebird": "^3.7.1",
"debug": "^4.1.1",
"dottie": "^2.0.0",
"inflection": "1.12.0",
......@@ -56,7 +55,7 @@
"chai-as-promised": "^7.x",
"chai-datetime": "^1.x",
"chai-spies": "^1.x",
"continuation-local-storage": "^3.x",
"cls-hooked": "^4.2.2",
"cross-env": "^5.2.1",
"env-cmd": "^8.0.2",
"esdoc": "^1.1.0",
......
......@@ -5,26 +5,24 @@ const chai = require('chai'),
Support = require('./support'),
Sequelize = Support.Sequelize,
Promise = Sequelize.Promise,
cls = require('continuation-local-storage'),
cls = require('cls-hooked'),
current = Support.sequelize;
if (current.dialect.supports.transactions) {
describe(Support.getTestDialectTeaser('Continuation local storage'), () => {
before(function() {
this.thenOriginal = Promise.prototype.then;
Sequelize.useCLS(cls.createNamespace('sequelize'));
describe(Support.getTestDialectTeaser('CLS (Async hooks)'), () => {
before(() => {
current.constructor.useCLS(cls.createNamespace('sequelize'));
});
after(() => {
cls.destroyNamespace('sequelize');
delete Sequelize._cls;
});
beforeEach(function() {
return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
this.sequelize = sequelize;
this.ns = cls.getNamespace('sequelize');
this.User = this.sequelize.define('user', {
name: Sequelize.STRING
});
......@@ -36,7 +34,7 @@ if (current.dialect.supports.transactions) {
it('does not use continuation storage on manually managed transactions', function() {
return Sequelize._clsRun(() => {
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();
});
});
......@@ -143,12 +141,14 @@ if (current.dialect.supports.transactions) {
});
});
});
});
it('bluebird patch is applied', function() {
expect(Promise.prototype.then).to.be.a('function');
expect(this.thenOriginal).to.be.a('function');
expect(Promise.prototype.then).not.to.equal(this.thenOriginal);
it('automagically uses the transaction in all calls with async/await', function() {
return this.sequelize.transaction(async () => {
await this.User.create({ name: 'bob' });
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() {
......
......@@ -4,19 +4,18 @@ const chai = require('chai'),
expect = chai.expect,
Support = require('../support'),
current = Support.sequelize,
cls = require('continuation-local-storage'),
cls = require('cls-hooked'),
sinon = require('sinon'),
stub = sinon.stub;
describe(Support.getTestDialectTeaser('Model'), () => {
describe('method findOrCreate', () => {
before(() => {
current.constructor.useCLS(cls.createNamespace('sequelize'));
});
after(() => {
cls.destroyNamespace('sequelize');
delete current.constructor._cls;
});
......@@ -36,7 +35,6 @@ describe(Support.getTestDialectTeaser('Model'), () => {
});
it('should use transaction from cls if available', function() {
const options = {
where: {
name: 'John'
......@@ -54,7 +52,6 @@ describe(Support.getTestDialectTeaser('Model'), () => {
});
it('should not use transaction from cls if provided as argument', function() {
const options = {
where: {
name: 'John'
......
......@@ -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
* project, create a namespace and set it on the sequelize constructor:
*
* ```js
* const cls = require('continuation-local-storage'),
* ns = cls.createNamespace('....');
* const cls = require('cls-hooked');
* const namespace = cls.createNamespace('....');
* 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
*
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!