-
Notifications
You must be signed in to change notification settings - Fork 502
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
Conversation
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.
585ec8f
to
8d8cfc5
Compare
I quickly checked the PR (will do a full review later if @tamirms and @leighmcculloch feel strongly about it) and I think the use of It would be a different story if we were passing a connection pool that's shared by all the requests (like we did before 9161997). |
@bartekn I understand your point of view. I'm not certain that this PR is significantly better than the old code given the added boilerplate. Another option would be to call I can't think of a way to completely eliminate the boilerplate code without relying on context values |
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.
There is a some extra boilerplate
@tamirms On first glance for someone who hasn't read this code before the changes definitely appeared quite complex. But after looking through the change this is really just moving existing logic around. I don't see a lot of new logic being added, what's the boilerplate you're referring to?
I think this does a good job of making it clear that the handler is dependent on the history.Q
since it is now included in the handler's struct and its constructor. I have one question inline, but it's more thinking out loud and asking a question than suggesting a change.
The DB connection/transaction is request scoped after 9161997 and I think this is exactly the use case of context
@bartekn The dependency (DB connection) is limited to this request, but not everything limited to this request belongs in the context. It's still a required dependency being injected. The code will break without it and we should make it explicit that it is needed either by including it in a function signature, type constructor, or as a field on the handler's type. Putting it in the context obscures it from view and it's a lot harder to keep track of what the dependencies of our code are if they aren't explicit.
There are a few good blog posts on this, my favourite probably being this one:
https://peter.bourgon.org/blog/2016/07/11/context.html
But also, this isn't a hard Go rule we're breaking. We can use context in any way we want to, it's a tradeoff. Is the convenience of passing the dependency around using context worth the tradeoff of reducing the clarity of the dependencies in our code? I don't think so, but you might disagree.
I think this looks good, but I don't feel qualified to ✅this PR alone. There's a lot going on here that I don't have much context. If the PR is to be merged @bartekn should 👀too.
My understanding is that for each action we need an extra function that creates a transaction. The reason we decided to rewrite actions is to remove a need for duplicate code so we try to avoid it now if possible.
I understand the reasoning here and I'm for dependency injection, I advocated several times to use automatic dependency injection (something like
Is it fine for you if we think about it more and decide what to do? I think we should really try to avoid another rewrite of actions package in the near future. |
HistoryQ *history.Q | ||
} | ||
|
||
// NewAccounts returns a PageHandler for the `/accounts` endpoint | ||
func NewAccounts(historyQ *history.Q) PageHandler { |
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 use NewAccountsHandler
-- it's more explicit about what we are getting.
If we are considering automatic dependency injection, we should evaluate https://github.com/google/wire which does compile time dependency injection instead of injection using reflection.
I don't think this is a fact. |
PR Checklist
PR Structure
otherwise).
services/friendbot
, orall
ordoc
if the changes are broad or impact manypackages.
Thoroughness
.md
files, etc... affected by this change). Take a look in the
docs
folder for a given service,like this one.
Release planning
needed with deprecations, added features, breaking changes, and DB schema changes.
semver, or if it's mainly a patch change. The PR is targeted at the next
release branch if it's not a patch change.
Summary
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.
See #1847 (comment) for more background on the motivation for this change.
Known limitations & issues
There is a some extra boilerplate compared to passing the db session via the request context