Skip to content
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

Merged
merged 1 commit into from
Jun 2, 2021

Conversation

matthiashanel
Copy link
Contributor

@matthiashanel matthiashanel commented Jun 1, 2021

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.

Copy link
Member

@kozlovic kozlovic left a 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 {
Copy link
Member

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.

Copy link
Member

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..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

Copy link
Contributor Author

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()

Copy link
Member

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.

Copy link
Member

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)
Copy link
Member

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.

Copy link
Contributor Author

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>
@coveralls
Copy link

Coverage Status

Coverage increased (+0.04%) to 86.978% when pulling efed691 on move-account-lookup into da90d22 on master.

@@ -192,15 +192,6 @@ func (nc *Conn) JetStream(opts ...JSOpt) (JetStreamContext, error) {
}
nc.mu.Unlock()

if checkAccount {
Copy link
Member

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 {
Copy link
Member

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
Copy link
Member

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.

Copy link
Contributor Author

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

Copy link
Member

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
Copy link
Member

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 {}

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

@derekcollison derekcollison self-requested a review June 2, 2021 21:25
Copy link
Member

@derekcollison derekcollison left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@matthiashanel matthiashanel merged commit 1267a88 into master Jun 2, 2021
@matthiashanel matthiashanel deleted the move-account-lookup branch June 2, 2021 22:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants