T
TanStack5mo ago
absent-sapphire

DB Transaction, AsyncLocalStorage and Middleware

Hello, I'm trying to add an abstraction for db transaction using Drizzle-ORM. For this I want to create a transaction and put it in the AsyncLocalStorage of Node.js, so that I can retrieve it using a function in my repositories without passing the transaction everywhere. Can I do this sort of things with the middleware ?
export const transactionMiddleware = createMiddleware().server(async ({ next }) => {
try {
const result = await db.transaction(async (tx) => {
const handlerResult = await dbTransactionLocalStorage.run(tx, async () => {
return await next();
});
return handlerResult;
});
return result;
}
catch (error) {
console.error("Transaction failed:", error);
throw error;
}
});

export const dbTransactionLocalStorage = new AsyncLocalStorage<TransactionClient>();

export const getDbClient = () => {
const transactionalClient = dbTransactionLocalStorage.getStore();
return transactionalClient || db;
}
export const transactionMiddleware = createMiddleware().server(async ({ next }) => {
try {
const result = await db.transaction(async (tx) => {
const handlerResult = await dbTransactionLocalStorage.run(tx, async () => {
return await next();
});
return handlerResult;
});
return result;
}
catch (error) {
console.error("Transaction failed:", error);
throw error;
}
});

export const dbTransactionLocalStorage = new AsyncLocalStorage<TransactionClient>();

export const getDbClient = () => {
const transactionalClient = dbTransactionLocalStorage.getStore();
return transactionalClient || db;
}
Because at first this seems to work but then after like 5-10 seconds the server just shutdown with only an error code (no other information):
Process finished with exit code -1073741819 (0xC0000005)
Process finished with exit code -1073741819 (0xC0000005)
Thanks in advance :).
1 Reply
foreign-sapphire
foreign-sapphire5mo ago
Hey, I usually put things inside the "event.context" and then retrieve them wherever I need. Something like this could work:
export const transactionMiddleware = createMiddleware().server(async ({ next }) => {
const event = getEvent()
const db = createDatabaseClient()
event.context.db = db // You can access this value using "getEvent().context.db"

return next({
context: {
db, // You can access this value accessing the context param directly
},
})
})

export function getDatabase() { // Use this function anywhere
const event = getEvent()
return event.context.db
}
export const transactionMiddleware = createMiddleware().server(async ({ next }) => {
const event = getEvent()
const db = createDatabaseClient()
event.context.db = db // You can access this value using "getEvent().context.db"

return next({
context: {
db, // You can access this value accessing the context param directly
},
})
})

export function getDatabase() { // Use this function anywhere
const event = getEvent()
return event.context.db
}
You can register it as global middleware, so the db is always available on the context

Did you find this page helpful?