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

Pass warnings through on non-error responses #599

Merged
merged 2 commits into from
Jun 13, 2019

Conversation

jacksontj
Copy link
Contributor

@jacksontj jacksontj commented Jun 8, 2019

Signed-off-by: Thomas Jackson jacksontj.89@gmail.com

Without this we have 2 problems:

(1) we cannot differentiate an error from a warning from the API response body (as the Err() method is returning self always

(2) we can inadvertently layer these errors together when using NewErrorAPI

This PR addresses both.

@jacksontj jacksontj force-pushed the warnings branch 2 times, most recently from 52a4612 to 7eda99c Compare June 8, 2019 05:52
@jacksontj
Copy link
Contributor Author

On a related note, I've been trying to integrate this warnings behavior as a client and I have to say the behavior/interface is infuriating to use.

According to the upstream prom docs the warnings are meant to be non-fatal. If the response has a warning and no error we currently return an Error type which implements the error interface. This is a bit clunky for direct usage, but manageable. If you are layering methods this is completely untenable. In golang if the err is not nil methods generally don't pass the value back up. A basic case would look like:

func PassThrough() (interface{}, error) {
    v, err := DownstreamFunc()
    if err != nil {
        return nil, err
    }
    return v, nil

Since this client is returning a non-nil thing that is a warning (and implements erro), if you want to still get the value when there is a warning but not an error it requires changing all code you have written before -- and (worse) to change your coding habits moving forward (as this is very not idiomatic go). To show how messy this is an example of this passing-through would look like:

func PassThrough() (interface{}, error) {
    v, err := DownstreamFunc()
    if apiErr, ok := err.(api.Error); ok  {
        if apiErr.Err() != nil {
            return nil, apiErr
        }
    }
    return v, api.NewErrorAPI(err)

Assuming upstream plans on keeping this behavior (warnings are non-fatal) IMO we should change the signature to pass warning separate from error. As it stands you basically have to rewrite everything once and change passthrough funcs and future coding habits. If we were to change the return to (value, warnings, error) It would require the one rewrite of the caller of the client but avoid problems with layering/passthrough.

Thoughts?

cc @krasi-georgiev

@krasi-georgiev
Copy link
Contributor

@jacksontj yep looks like this implementation make the use of error quite bad so yeah lets try with your original suggestion.

@jacksontj
Copy link
Contributor Author

jacksontj commented Jun 11, 2019 via email

@jacksontj
Copy link
Contributor Author

@krasi-georgiev here is the change, for now I only wired up warnings to query/queryRange -- as they are the only ones that pass that information back. If these get added to others in the future it would be easy to add -- but I don't think thats planned.

res, err := test.do()
res, warnings, err := test.do()

if (test.inWarnings == nil) != (warnings == nil) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I am a bit confused by this. The queryTests don't have the inWarnings set anywhere so this will always be true test.inWarnings == nil

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@krasi-georgiev true, I've added a couple cases that do so.

Copy link
Contributor

Choose a reason for hiding this comment

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

but than you should also check the content right? testutil.Equals(t,test.inWarnings,warnings)

Copy link
Contributor

Choose a reason for hiding this comment

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

and don't forget the full stop for the comments to follow the golang standards. I know it is annoying until you get used to it 😸

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated again :)

@jacksontj jacksontj force-pushed the warnings branch 3 times, most recently from 98584bc to e384c03 Compare June 13, 2019 23:02
Signed-off-by: Thomas Jackson <jacksontj.89@gmail.com>
Signed-off-by: Thomas Jackson <jacksontj.89@gmail.com>
@krasi-georgiev
Copy link
Contributor

Thanks!

@jacksontj jacksontj deleted the warnings branch June 13, 2019 23:54
// Query performs a query for the given time.
Query(ctx context.Context, query string, ts time.Time) (model.Value, api.Error)
Query(ctx context.Context, query string, ts time.Time) (model.Value, api.Warnings, error)

Choose a reason for hiding this comment

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

This breaks a lot of downstream users of this library who have been relying on go get without a lock file

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately this was expected, upstream prometheus added these warnings and due to the semantics of those warnings we end up basically requiring this (more discussion in #562).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Personally I'm finding this Warnings thing a major pain to integrate as it complicates things quite a bit more (and it doesn't really help IMO that its not really a "warning" from prometheus).

@verdverm
Copy link

verdverm commented Jun 14, 2019 via email

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.

None yet

3 participants