-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: reduce request transaction lifetime #3299
Conversation
@@ -86,6 +92,7 @@ func authenticateRequest(c *gin.Context, tx *data.Transaction, srv *Server) erro | |||
return internal.ErrBadRequest | |||
} | |||
|
|||
// TODO: move to caller |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that the transaction is separate, the only thing these two functions provide is the access.Authenticated
struct. So I think we can return that directly instead of mutating the gin.Context
.
I'm going to look to address these TODOs in a follow up PR. It requires a few changes to handleInfraDestinationHeader
.
@@ -75,7 +75,13 @@ func handleInfraDestinationHeader(c *gin.Context) error { | |||
// gin.Context. | |||
// See validateRequestOrganization for a related function used for unauthenticated | |||
// routes. | |||
func authenticateRequest(c *gin.Context, tx *data.Transaction, srv *Server) error { | |||
func authenticateRequest(c *gin.Context, srv *Server) error { | |||
tx, err := srv.db.Begin(c.Request.Context()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will still work without explicitly starting a transaction, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, I guess that is true. I haven't looked at all the queries, but it might be ok without an explicit transaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think there is any advantage to not using a transaction? I thought generally we would want to put things into short lived transactions.
@@ -131,7 +142,13 @@ func validateOrgMatchesRequest(req *http.Request, tx data.GormTxn, accessKeyOrg | |||
// | |||
// validateRequestOrganization is also responsible for adding RequestContext to the | |||
// gin.Context. | |||
func validateRequestOrganization(c *gin.Context, tx *data.Transaction, srv *Server) error { | |||
func validateRequestOrganization(c *gin.Context, srv *Server) error { | |||
tx, err := srv.db.Begin(c.Request.Context()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also optional?
PostgreSQL row and table locks are held until the end of the transaction. Previously we were using a single transaction for the entire lifetime of the request. One of the first things we did with that transaction was update the access key and user record associated with the request. That update would block any other requests from that user until the first request finished. For short lived requests that was fine, but longer requests (anything making HTTP requests to an IDP, or blocking and waiting for updates) would prevent the user from making concurrent requests. This commit fixes the problem by committing the "middleware" transaction first, then starting a new transaction for the request handler. The middleware transaction should be short lived, because does only a few database operations and returns. It doesn't block or make external requests.
b697a95
to
ee92dec
Compare
PostgreSQL row and table locks are held until the end of the transaction.
Previously we were using a single transaction for the entire lifetime of the request. One of the first things we did with that transaction was update the access key and user record associated with the request.
That update would block any other requests from that user until the first request finished. For short lived requests that was fine, but longer requests (anything making HTTP requests to an IDP, or blocking and waiting for updates) would prevent the user from making concurrent requests.
This commit fixes the problem by committing the "middleware" transaction first, then starting a new transaction for the request handler. The middleware transaction should be short lived, because it only does a few database operations and returns. It doesn't block or make external requests.