-
Notifications
You must be signed in to change notification settings - Fork 696
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
[changed] JetStream function to not lookup account info & moved it #739
Conversation
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.
Not commenting on the validity of the move, just noticed inconsistencies.
This is concerning since I just started working on the C client (was waiting for the Go client to be done) and the first function I implemented is the the equivalent of JetStream() (get the context, which would call js.AccountInfo()) and that is already changing :-)
@@ -192,15 +192,6 @@ func (nc *Conn) JetStream(opts ...JSOpt) (JetStreamContext, error) { | |||
} | |||
nc.mu.Unlock() | |||
|
|||
if checkAccount { |
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.
If that disappears, then above jsLastCheck
should disappear too and be removed from the Conn
object.
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.
By the way, existing code is broken: if one calls JetStream() for the first time and say the overall call fails (JetStream not enabled, or custom prefix leads nowhere), then the second call to JetStream() would succeed because we would not check for the AccountInfo().. so this is bad. At the very least if "time check" is maintained, we should record jsLastCheck only on success. But still, it means that the next call to JetStream() may succeed even if the underlying AccountInfo() would have failed because we passed a bad prefix, etc..
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.
fixed.
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.
fixed. JetStream() is now a constructor only. because it can't reallly fail, we can use js.AccountInfo()
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.
The time check bug was me, and agree we should only stamp (if we keep it) on success.
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.
I am still not clear (and this is me, not the code) as to why we are doing this change vs an option like SkipAccountCheck().
This feels like it could jarring to only catch the you do not have JetStream enabled when you make a secondary call, but maybe that is ok here. Originally before domains and api prefixes it felt like the natural place to check this and return that error.
nats.go
Outdated
defer cancel() | ||
} | ||
|
||
resp, err := nc.RequestWithContext(o.ctx, jOpts.apiSubj(apiAccountInfo), nil) |
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.
If user provides a different prefix than the one registered when initially getting the context, then should not this prefix be used instead? In other words, should it be o.apiSubj()
here? (if I understand correctly o
is the mix of the default's js options and the user provided one.
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.
fixed. instead of moving code we now use js.AcccountInfo (that existed before)
Removded then lookup of account info. now already existing js.AccountInfo has to be called separately. Signed-off-by: Matthias Hanel <mh@synadia.com>
f7b41e7
to
efed691
Compare
@@ -192,15 +192,6 @@ func (nc *Conn) JetStream(opts ...JSOpt) (JetStreamContext, error) { | |||
} | |||
nc.mu.Unlock() | |||
|
|||
if checkAccount { |
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.
The time check bug was me, and agree we should only stamp (if we keep it) on success.
@@ -192,15 +192,6 @@ func (nc *Conn) JetStream(opts ...JSOpt) (JetStreamContext, error) { | |||
} | |||
nc.mu.Unlock() | |||
|
|||
if checkAccount { |
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.
I am still not clear (and this is me, not the code) as to why we are doing this change vs an option like SkipAccountCheck().
This feels like it could jarring to only catch the you do not have JetStream enabled when you make a secondary call, but maybe that is ok here. Originally before domains and api prefixes it felt like the natural place to check this and return that error.
@@ -170,6 +170,8 @@ type accountInfoResponse struct { | |||
} | |||
|
|||
// AccountInfo retrieves info about the JetStream usage from the current account. | |||
// If JetStream is not enabled, this will return ErrJetStreamNotEnabled |
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 now has to be the case for every API call to the JS context, but I think that is ok.
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.
@wallyqs we need to probably go through our public calls and make sure that is so
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.
yes could happen if JS becomes disabled
@@ -496,9 +496,6 @@ type Conn struct { | |||
respMux *Subscription // A single response subscription | |||
respMap map[string]chan *Msg // Request map for the response msg channels | |||
respRand *rand.Rand // Used for generating suffix | |||
|
|||
// JetStream Contexts last account check. | |||
jsLastCheck time.Time |
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.
I think we all agreed that JS contexts should be lightweight and easy to create. In many tests I create multiple ones with different characteristics.
Question though, do we expect code to look like this all the time or folks will skip the AccountInfo and just check errors on the other API calls?
nc, _ := nc.Connect("demo.nats.io")
js, _ := nc.JetStream()
if _, err := js.AccountInfo(); err != nil {}
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.
Help me understand: can the enabled/disabled nature of JetStream for this connection change overtime? Meaning, after calling JetStream() (and lets say we still do an account check inside, and it returned ok), is there a possibility that JS may no longer be enabled for this account? What if the connection reconnects to a server where this account does not have JS enabled, which likely would be misconfiguration?
If it can't change, then instead of a time check, it should be simply a "already checked and here is the result" type of things (say 2 booleans).
If it can change overtime and since all APIs will return "not enabled" if JS is or no longer is enabled, not sure what we gain by doing it inside JetStream(). Say you already have the context, but then JS is disabled, then the context is "valid" and yet all other APIs call will fail with "not enabled". Same if you recently got a context and we use time-check, then if we are within the window, JetStream() would return a context (which won't work when calling APIs), but if you happen to ask after the time-check has passed, this call would return "not enabled".
I am not against doing the account check inside JetStream() (with the time-check bug fixed), since it can give a "fail fast" behavior where if you get "not enabled", there is no need to proceed further, but it also can be non deterministic (as described above), and all APIs should be checked for success/failure anyway.
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.
due to reload or jwt update Js can be legitimately enabled disabled on the fly.
We have code that turns a no responder into the same error, so flapping because of that can happen as well.
If you want to fail fast, perhaps for debugging, I'd suggest call js.AccountInfo.
I'd also suggest calling that function on retries. you fails for some reason now you can better determine if retrying makes sense or not.
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.
I think for users that want to ensure that JS is ready and available, a bit more code would be needed which might be better to have outside of the creation of the JetStream()
context:
nc, _ := nc.Connect("demo.nats.io")
js, _ := nc.JetStream()
ctx, done := context.WithTimeout(context.Background(), 5*time.Second)
defer done()
// IsJSAvailable()
for {
select {
case <-ctx.Done():
return
default:
}
if _, err := js.AccountInfo(); err != nil {
// Handle temporary errors:
//
// - Quorum not ready
// - JS API not yet ready
// - No responders (temporary while JS booting up)
// Then: timeout when too many failures or no response
}
}
There would be some retries when this happens for example and backoff until is ready.
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.
LGTM
The new function is JSAccountInfo
Signed-off-by: Matthias Hanel mh@synadia.com
This separates concerns into give me a jetstream object and check jetstream.
Moving that logic to the nats connection to avoid dependencies with the JetStream call.
In our meeting the group generally favored opt in over opt out.
I'm clearly expecting ppl to either copy a sample anyway and there we add the call of course.
Or if they run into this, to just ask & find this new call.
it's also opt in because the main thing that the lookup does is provide a different error.
I noticed that the unit test for the js object appears to be broken right now. (at least for me, even without my change)
Deleted the checks so I could show you this sooner.
If that approach is not desirec, I'll revert and add an option to opt out of the lookup.