-
Notifications
You must be signed in to change notification settings - Fork 504
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
services/horizon/internal/actions: Remove inappropriate use of context in ingestion endpoints #1861
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Remove inappropriate use of context in ingestion endpoints
Commit 9161997 used a request context to ensure that all queries to the horizon database from ingestion endpoints were wrapped in a repeatable read transaction. This commit refactors the ingestion endpoints to acheive the same effect without using a context to store a request scoped database session.
- Loading branch information
commit 8d8cfc5e4958832881bd7ed878fa22d247aae539
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package actions | ||
|
||
import ( | ||
"database/sql" | ||
"net/http" | ||
"strconv" | ||
|
||
"github.com/stellar/go/services/horizon/internal/db2/history" | ||
"github.com/stellar/go/support/errors" | ||
"github.com/stellar/go/support/render/hal" | ||
) | ||
|
||
// LastLedgerHeaderName is the header which is set on all experimental ingestion endpoints | ||
const LastLedgerHeaderName = "Latest-Ledger" | ||
|
||
// HeaderWriter is an interface for setting HTTP response headers | ||
type HeaderWriter interface { | ||
Header() http.Header | ||
} | ||
|
||
// StreamableObjectResponse is an interface for objects returned by streamable object endpoints | ||
// A streamable object endpoint is an SSE endpoint which returns a single JSON object response | ||
// instead of a page of items. | ||
type StreamableObjectResponse interface { | ||
Equals(other StreamableObjectResponse) bool | ||
} | ||
|
||
// PageHandler represents a handler for a horizon endpoint which produces a response body | ||
// consisting of a list of `hal.Pageable` items | ||
type PageHandler interface { | ||
GetResourcePage(w HeaderWriter, r *http.Request) ([]hal.Pageable, error) | ||
} | ||
|
||
// StreamableObjectHandler represents a handler for a horizon endpoint which produces a | ||
// response body consisting of a single `StreamableObjectResponse` instance | ||
type StreamableObjectHandler interface { | ||
GetResource( | ||
w HeaderWriter, | ||
r *http.Request, | ||
) (StreamableObjectResponse, error) | ||
} | ||
|
||
// ObjectHandler represents a handler for a horizon endpoint which produces a | ||
// response body consisting of a single `hal.Pageable` instance | ||
type ObjectHandler interface { | ||
GetResource( | ||
w HeaderWriter, | ||
r *http.Request, | ||
) (hal.Pageable, error) | ||
} | ||
|
||
func repeatableReadSession(source *history.Q, r *http.Request) (*history.Q, error) { | ||
repeatableReadSession := source.Clone() | ||
repeatableReadSession.Ctx = r.Context() | ||
err := repeatableReadSession.BeginTx(&sql.TxOptions{ | ||
Isolation: sql.LevelRepeatableRead, | ||
ReadOnly: true, | ||
}) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "could not begin repeatable read transaction") | ||
} | ||
return &history.Q{repeatableReadSession}, nil | ||
} | ||
|
||
// SetLastLedgerHeader sets the Latest-Ledger header | ||
func SetLastLedgerHeader(w HeaderWriter, lastIngestedLedger uint32) { | ||
w.Header().Set(LastLedgerHeaderName, strconv.FormatUint(uint64(lastIngestedLedger), 10)) | ||
} | ||
|
||
func fetchAndSetLastLedgerHeader(w HeaderWriter, historyQ *history.Q) error { | ||
lastIngestedLedger, err := historyQ.GetLastLedgerExpIngestNonBlocking() | ||
if err != nil { | ||
return errors.Wrap(err, "could not determine last ingested ledger") | ||
} | ||
|
||
SetLastLedgerHeader(w, lastIngestedLedger) | ||
return nil | ||
} | ||
|
||
type repeatableReadPageHandler struct { | ||
historyQ *history.Q | ||
withQ func(*history.Q) PageHandler | ||
} | ||
|
||
func (handler repeatableReadPageHandler) GetResourcePage( | ||
w HeaderWriter, | ||
r *http.Request, | ||
) ([]hal.Pageable, error) { | ||
historyQ, err := repeatableReadSession(handler.historyQ, r) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer historyQ.Rollback() | ||
|
||
if err = fetchAndSetLastLedgerHeader(w, historyQ); err != nil { | ||
return nil, err | ||
} | ||
|
||
return handler.withQ(historyQ).GetResourcePage(w, r) | ||
} | ||
|
||
type repeatableReadObjectHandler struct { | ||
historyQ *history.Q | ||
withQ func(*history.Q) ObjectHandler | ||
} | ||
|
||
func (handler repeatableReadObjectHandler) GetResource( | ||
w HeaderWriter, | ||
r *http.Request, | ||
) (hal.Pageable, error) { | ||
historyQ, err := repeatableReadSession(handler.historyQ, r) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer historyQ.Rollback() | ||
|
||
if err = fetchAndSetLastLedgerHeader(w, historyQ); err != nil { | ||
return nil, err | ||
} | ||
|
||
return handler.withQ(historyQ).GetResource(w, r) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
@tamirms shall we use the same convention as we were using before so it's clear that we are creating a handler? so instead of
NewAccounts
we useNewAccountsHandler
-- it's more explicit about what we are getting.