You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi, I'm seeing some weird "context leaking" in my express app where occasionally, 1 user seems to get the data of another user and I just want to confirm if my usage of cls-hooked below is correct. Some bits are omitted/shortened for simplicity.
The /some-mutation endpoint, starts a database transaction that spans the request, calls a bunch of domain functions that update the database and then calls commit/rollback on the transaction.
getDBConn returns a db connection from request context if present, otherwise it returns a new connection. A connection being present in the requestContext essentially means there is a request wide database transaction happening.
startRequestTransaction gets a fresh db connection, starts a transaction and stores it in requestContext for all subsequent database functions to consume.
doThingA and doThingB are functions that hit the database. They're unaware of whether they're in a transaction or not, that's decided for them further up and they just work with whatever connection is returned by getDBConn
import{createNamespace}from'cls-hooked'exportconstrequestContext=createNamespace('request-context')constapp=express()app.use(functionrequestContextMiddleware(req,res,next){requestContext.run(()=>next())})app.use(functionsetAuthenticatedUser(req,res,next){// if request has auth headerrequestContext.set('authenticated-user',{})})constrouter=express.Router()router.get('/some-mutation',async()=>{try{awaitstartRequestTransaction()awaitdoThingA()awaitdoThingB()awaitcommitRequestTransaction()}catch(error){awaitrollbackRequestTransaction()}})asyncfunctionstartRequestTransaction(){constdbConn=awaitgetDBConn()awaitdbConn.startTransaction()requestContext.set('request-transaction',dbConn)}asyncfunctioncommitRequestTransaction(){constdbConn=requestContext.get('request-transaction')awaitdbConn.commit()requestContext.set('request-transaction',null)}asyncfunctionrollbackRequestTransaction(){constdbConn=requestContext.get('request-transaction')awaitdbConn.rollback()requestContext.set('request-transaction',null)}asyncfunctiongetDBConn(){return(requestContext.get('request-transaction')||getNewDBConnFromSomewhere())}asyncfunctiondoThingA(){constdbConn=awaitgetDBConn()awaitdbConn.query('...')awaitdbConn.insert('...')}asyncfunctiondoThingB(){constdbConn=awaitgetDBConn()awaitdbConn.query('...')awaitdbConn.insert('...')}
Is this supposed to work? I also see runPromise mentioned in threads and issues but it's not mentioned in the docs at all. Is it better to use runPromise when you have lots of async function consuming the context downstream?
I can see there are some issues of similar nature still open but not sure if they're resolved. Does this approach just not work when there's async code involved?
Any help would be appreciated as this is happening in a prod app for us, we went all in on cls-hooked as it allowed us to have very simple domain logic code, didn't anticipate running into something like this.
The text was updated successfully, but these errors were encountered:
Hi, I'm seeing some weird "context leaking" in my express app where occasionally, 1 user seems to get the data of another user and I just want to confirm if my usage of cls-hooked below is correct. Some bits are omitted/shortened for simplicity.
/some-mutation
endpoint, starts a database transaction that spans the request, calls a bunch of domain functions that update the database and then calls commit/rollback on the transaction.getDBConn
returns a db connection from request context if present, otherwise it returns a new connection. A connection being present in therequestContext
essentially means there is a request wide database transaction happening.startRequestTransaction
gets a fresh db connection, starts a transaction and stores it inrequestContext
for all subsequent database functions to consume.doThingA
anddoThingB
are functions that hit the database. They're unaware of whether they're in a transaction or not, that's decided for them further up and they just work with whatever connection is returned bygetDBConn
Is this supposed to work? I also see
runPromise
mentioned in threads and issues but it's not mentioned in the docs at all. Is it better to userunPromise
when you have lots of async function consuming the context downstream?I can see there are some issues of similar nature still open but not sure if they're resolved. Does this approach just not work when there's async code involved?
Any help would be appreciated as this is happening in a prod app for us, we went all in on cls-hooked as it allowed us to have very simple domain logic code, didn't anticipate running into something like this.
The text was updated successfully, but these errors were encountered: