MiNiMAL
MiNiMAL9mo ago

Function to release context post-batching?

In our application every customer has their own schema, therefore we need a db client per request which I was hoping to leverage with TRPC context. Ideally, we'd be able to: - Connect to the database in context ✅ - Set the search_path to match the client's JWT in context ✅ - Run our procedures using that database connection from context ✅ - Release the database connection after all batching is finished ❌ Is this not currently possible with TRPC? Right now I think I can only connect to the database using a per procedure middleware.
const db = // connect to db

await db.execute('SET search_path=...')

try {
return await next({ ctx: { ...opts.ctx, db } })
} catch () {
// release connection
} finally {
// release connection
}
const db = // connect to db

await db.execute('SET search_path=...')

try {
return await next({ ctx: { ...opts.ctx, db } })
} catch () {
// release connection
} finally {
// release connection
}
This works, but it requires establishing a connection/search_path for every procedure in a batch, instead of just once in context and releasing after the batch. Is there a way to accomplish this?
5 Replies
Alex / KATT 🐱
Maybe you can do some lazy getter in async local storage? Oh yeah hear you I'll think about it, maybe there's something we could do
Alex / KATT 🐱
GitHub
refactor(server): removes teardown option by ixahmedxi · Pull Reque...
Closes # 🎯 Changes What changes are made in this PR? Is it a feature or a bug fix? As discussed previously, this PR removes the teardown function option. ✅ Checklist I have followed the steps lis...
MiNiMAL
MiNiMAL9mo ago
Thanks, I'll peek at that. I'm also going to experiment with moving the db connection logic onto the express middleware layer Was there a reason for the removal of teardown? I'm happy to suggest reverting but lack the context.
Alex / KATT 🐱
I didn't think anyone was using it and we did a new major Just housekeeping Just make sure the teardown gets the context as an arg
MiNiMAL
MiNiMAL9mo ago
@Alex / KATT 🐱 I think I got this working just with express middleware. Somewhat hacky but...it's working!
app.use(async (req, res, next) => {
const client = await getClient()
req.client = client
next()
})

app.use('/trpc', async (req, res, next) => {
await createExpressMiddleware({
router: appRouter,
createContext,
})(req, res, next)
next()
})

app.use(async (req, res) => {
if (req.client) {
await req.client.release()
}
})
app.use(async (req, res, next) => {
const client = await getClient()
req.client = client
next()
})

app.use('/trpc', async (req, res, next) => {
await createExpressMiddleware({
router: appRouter,
createContext,
})(req, res, next)
next()
})

app.use(async (req, res) => {
if (req.client) {
await req.client.release()
}
})
and actually...this can be simplified into just one middleware for /trpc
app.use('/trpc', async (req, res, next) => {
const client = await getClient()
req.client = client

await createExpressMiddleware({
router: appRouter,
createContext
})(req, res, next)

if (req.client) {
await req.client.release()
}
})
app.use('/trpc', async (req, res, next) => {
const client = await getClient()
req.client = client

await createExpressMiddleware({
router: appRouter,
createContext
})(req, res, next)

if (req.client) {
await req.client.release()
}
})