From acfc0644c82936d0cf1544d35eca8f068df4ef97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98?= Date: Sun, 2 Oct 2022 16:08:02 +0700 Subject: [PATCH 1/6] docs: add manually retrying failed transactions section --- docs/other-topics/transactions.md | 78 +++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/docs/other-topics/transactions.md b/docs/other-topics/transactions.md index 054b8f6c6..11f70b346 100644 --- a/docs/other-topics/transactions.md +++ b/docs/other-topics/transactions.md @@ -222,6 +222,84 @@ const sequelize = new Sequelize('sqlite::memory:', { **Note for MSSQL:** _The `SET ISOLATION LEVEL` queries are not logged since the specified `isolationLevel` is passed directly to `tedious`._ +## Manually retrying failed transactions + +Sequelize does not automically retries on potential write conflicts for deadlocks, when using a certain level of isolation, it is expected that transactions may fail due to potential write conflicts due to concurrent transactions or deadlocks. + +You can programmatically fix this by relying on options from the [retry-as-promised](https://github.com/mickhansen/retry-as-promised/blob/master/README.md) library: + +```typescript +const { Sequelize } = require('@sequelize/core'); + +const sequelize = new Sequelize(process.env.DB_NAME, + process.env.DB_NAME, + process.env.DB_PASS, + { + host: process.env.DB_HOST, + dialect: 'mysql', + // Here: + retry: { + max: 3, // this may cause memory leaks if you set the retries limit too much. + match: [ + Sequelize.ConnectionError, + Sequelize.ConnectionRefusedError, + Sequelize.ConnectionTimedOutError, + Sequelize.OptimisticLockError, + Sequelize.TimeoutError, + /Deadlock/i, // retry-as-promised also takes RegExp, for example to find deadlocks error. + ], + } +}); +``` + +List of retry options and the default value: + +```js +{ + retry: { + $current: 1, + max: undefined, + timeout: undefined, + match: [], + backoffBase: 100, + backoffExponent: 1.1, + report: function () {}, + name: 'unknown', + } +} +``` + +You can use other possible error classes [here](https://sequelize.org/api/v7/classes/error). + +You can also fix this without relying on options from the `retry-as-promised` library: + +```typescript +const { Sequelize, Transaction } = require('@sequelize/core'); + +async function executeSomething() { + const MAX_RETRIES = 5 + let retriesCount = 0; + + let result; + while (retriesCount < MAX_RETRIES) { + try { + result = await sequelize.transaction({ + isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE + }, async (t) => { + // Your code + }); + } catch (error) { + // You can modify the script below to achieve your goals. + if (error.message === 'the error message') { + retriesCount++; + continue; + } + throw error; + } + } +} +``` + ## Usage with other sequelize methods The `transaction` option goes with most other options, which are usually the first argument of a method. From 16fd2d2e047b80a781f4008e920eb91b809214d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98?= Date: Sun, 2 Oct 2022 16:10:06 +0700 Subject: [PATCH 2/6] Add comma --- docs/other-topics/transactions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/other-topics/transactions.md b/docs/other-topics/transactions.md index 11f70b346..101d7794e 100644 --- a/docs/other-topics/transactions.md +++ b/docs/other-topics/transactions.md @@ -277,7 +277,7 @@ You can also fix this without relying on options from the `retry-as-promised` li const { Sequelize, Transaction } = require('@sequelize/core'); async function executeSomething() { - const MAX_RETRIES = 5 + const MAX_RETRIES = 5; let retriesCount = 0; let result; From f4d284c179fb1ef6ce522c329fc2a40a3950b5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98?= Date: Sun, 2 Oct 2022 16:11:54 +0700 Subject: [PATCH 3/6] fix: wording --- docs/other-topics/transactions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/other-topics/transactions.md b/docs/other-topics/transactions.md index 101d7794e..3be57cf0d 100644 --- a/docs/other-topics/transactions.md +++ b/docs/other-topics/transactions.md @@ -224,7 +224,7 @@ const sequelize = new Sequelize('sqlite::memory:', { ## Manually retrying failed transactions -Sequelize does not automically retries on potential write conflicts for deadlocks, when using a certain level of isolation, it is expected that transactions may fail due to potential write conflicts due to concurrent transactions or deadlocks. +Sequelize does not automically retries on potential write conflicts or deadlocks, when using a certain level of isolations, it is expected that transactions may fail due to potential write conflicts in concurrent transactions or deadlocks. You can programmatically fix this by relying on options from the [retry-as-promised](https://github.com/mickhansen/retry-as-promised/blob/master/README.md) library: From c1459e4f6fc5740b64c0d1d031806b7242df95ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98?= Date: Sun, 2 Oct 2022 16:26:57 +0700 Subject: [PATCH 4/6] docs; reorder and wording --- docs/other-topics/transactions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/other-topics/transactions.md b/docs/other-topics/transactions.md index 3be57cf0d..fbd05af18 100644 --- a/docs/other-topics/transactions.md +++ b/docs/other-topics/transactions.md @@ -252,7 +252,9 @@ const sequelize = new Sequelize(process.env.DB_NAME, }); ``` -List of retry options and the default value: +You can use other possible error classes [here](https://sequelize.org/api/v7/classes/error). + +List of the default retry options and the value when you passing `{}` to the retry option: ```js { @@ -269,8 +271,6 @@ List of retry options and the default value: } ``` -You can use other possible error classes [here](https://sequelize.org/api/v7/classes/error). - You can also fix this without relying on options from the `retry-as-promised` library: ```typescript From f3d2c8ee283866c1628185188292710246f15558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandcat=E4=BA=BA?= Date: Fri, 7 Oct 2022 06:56:38 +0700 Subject: [PATCH 5/6] docs: remove some parts --- docs/other-topics/transactions.md | 46 ------------------------------- 1 file changed, 46 deletions(-) diff --git a/docs/other-topics/transactions.md b/docs/other-topics/transactions.md index fbd05af18..ea51787f7 100644 --- a/docs/other-topics/transactions.md +++ b/docs/other-topics/transactions.md @@ -254,52 +254,6 @@ const sequelize = new Sequelize(process.env.DB_NAME, You can use other possible error classes [here](https://sequelize.org/api/v7/classes/error). -List of the default retry options and the value when you passing `{}` to the retry option: - -```js -{ - retry: { - $current: 1, - max: undefined, - timeout: undefined, - match: [], - backoffBase: 100, - backoffExponent: 1.1, - report: function () {}, - name: 'unknown', - } -} -``` - -You can also fix this without relying on options from the `retry-as-promised` library: - -```typescript -const { Sequelize, Transaction } = require('@sequelize/core'); - -async function executeSomething() { - const MAX_RETRIES = 5; - let retriesCount = 0; - - let result; - while (retriesCount < MAX_RETRIES) { - try { - result = await sequelize.transaction({ - isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE - }, async (t) => { - // Your code - }); - } catch (error) { - // You can modify the script below to achieve your goals. - if (error.message === 'the error message') { - retriesCount++; - continue; - } - throw error; - } - } -} -``` - ## Usage with other sequelize methods The `transaction` option goes with most other options, which are usually the first argument of a method. From 7fd4ec1cc96ed0c909a1f02dc950595476376fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandcat=E4=BA=BA?= Date: Sun, 9 Oct 2022 05:19:34 +0700 Subject: [PATCH 6/6] docs: add caution --- docs/other-topics/transactions.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/other-topics/transactions.md b/docs/other-topics/transactions.md index ea51787f7..900d6fb9b 100644 --- a/docs/other-topics/transactions.md +++ b/docs/other-topics/transactions.md @@ -222,7 +222,7 @@ const sequelize = new Sequelize('sqlite::memory:', { **Note for MSSQL:** _The `SET ISOLATION LEVEL` queries are not logged since the specified `isolationLevel` is passed directly to `tedious`._ -## Manually retrying failed transactions +## Manually retrying the failed transactions Sequelize does not automically retries on potential write conflicts or deadlocks, when using a certain level of isolations, it is expected that transactions may fail due to potential write conflicts in concurrent transactions or deadlocks. @@ -244,7 +244,6 @@ const sequelize = new Sequelize(process.env.DB_NAME, Sequelize.ConnectionError, Sequelize.ConnectionRefusedError, Sequelize.ConnectionTimedOutError, - Sequelize.OptimisticLockError, Sequelize.TimeoutError, /Deadlock/i, // retry-as-promised also takes RegExp, for example to find deadlocks error. ], @@ -254,6 +253,13 @@ const sequelize = new Sequelize(process.env.DB_NAME, You can use other possible error classes [here](https://sequelize.org/api/v7/classes/error). + +:::caution + +Be careful when manually retrying the transactions, this can lead to retries for the same reason (possible memory leak if you set `max` option value to a large number or `Infinity`), always check what was thrown. + +::: + ## Usage with other sequelize methods The `transaction` option goes with most other options, which are usually the first argument of a method.