Created
May 29, 2020 12:19
-
-
Save ephys/3c51f5558ae9f3ac3d4994080c93b7d8 to your computer and use it in GitHub Desktop.
sequelize's transaction and async_hooks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @flow | |
import { AsyncLocalStorage } from 'async_hooks'; | |
import type { Sequelize, Transaction } from 'sequelize'; | |
const asyncStore = new AsyncLocalStorage(); | |
/** | |
* This works like {@link Sequelize#transaction}, but if this is called inside an active transaction, | |
* the active transaction will be returned. | |
* | |
* Note: You should use this as a replacement for {@link Sequelize#transaction}, | |
* otherwise {@link getCurrentTransaction} will break. | |
* | |
* Note: SAVEPOINT functionality has not been implemented, if a sub-transaction fail, | |
* you should let the whole transaction fail or you'll end-up with inconsistent state. | |
* If SAVEPOINT is needed, ping @ephys | |
* | |
* @param {!Sequelize} sequelize The sequelize instance on which the transaction will run | |
* @param {!Function} callback The callback to call with the transaction. | |
* | |
* @returns {any} The returned value of {callback} | |
*/ | |
export function withTransaction<T>(sequelize: Sequelize, callback: (t: Transaction) => T) { | |
const transaction = getCurrentTransaction(); | |
if (transaction) { | |
return callback(transaction); | |
} | |
return sequelize.transaction(async newTransaction => { | |
return asyncStore.run(newTransaction, () => { | |
return callback(newTransaction); | |
}); | |
}); | |
} | |
/** | |
* Returns the transaction of the current {@link withTransaction} block, if any. | |
* | |
* This method does not create a new transaction if none is active. | |
* | |
* @returns {Transaction | null} The transaction | |
*/ | |
export function getCurrentTransaction(): Transaction | null { | |
return asyncStore.getStore() ?? null; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// AFTER | |
function sendMessage(from, to, message) { | |
return withTransaction(sequelize, () => { | |
const conversation = await createConversation(from, to); | |
return await createMessage(conversation, from, message); | |
}); | |
} | |
function createConversation(from, to) { | |
Conversation.create(stuff, { transaction: getCurrentTransaction() }); | |
} | |
function createMessage(conversation, from, message) { | |
Message.create(stuff, { transaction: getCurrentTransaction() }); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// BEFORE | |
function sendMessage(from, to, message) { | |
return sequelize.transaction(transaction => { | |
const conversation = await createConversation(from, to, { transaction }); | |
return await createMessage(conversation, from, message, { transaction }); | |
}); | |
} | |
function createConversation(from, to, { transaction }) { | |
Conversation.create(stuff, { transaction }); | |
} | |
function createMessage(conversation, from, message, { transaction }) { | |
Message.create(stuff, { transaction }); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment