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

Feature/receive server query #70

Merged
merged 5 commits into from
Aug 28, 2024
Merged

Conversation

yuzifeng1984
Copy link
Collaborator

Update protocol to support receiving query id from server

* Implement elapsed time in query progress

* add debug
@yuzifeng1984 yuzifeng1984 force-pushed the feature/receive-server-query-id branch from 27915c3 to 0980329 Compare July 29, 2024 04:59
@yuzifeng1984
Copy link
Collaborator Author

yuzifeng1984 commented Aug 20, 2024

@chenziliang @ye11ow

I merged proton PR to encode server node id into query UUID in https://github.com/timeplus-io/proton-enterprise/pull/5460

This golang driver PR is to receive the server generated query ID and return it to the caller. In order to use the query id (eg. kill query/get pipeline in cluster), caller need provide callback function in QueryOption as below. Please help to review the PR.

func WithReceiveQueryID(fn func(string)) QueryOption {
	return func(o *QueryOptions) error {
		o.events.receiveQueryID = fn
		return nil
	}
}

Also refer to ut code.
https://github.com/timeplus-io/proton-go-driver/pull/70/files#diff-9f2a2381e0cc03e4ae97084cd3fb6b580de684a4e63963f843ff99078e5b5048

@ye11ow
Copy link
Collaborator

ye11ow commented Aug 21, 2024

@yuzifeng1984 I'm purely speaking from the user side (the user of proton-go-driver):
The current approach looks weird to me. For the TestServerGenerateQueryID I'd expect something like

ctx = proton.Context(context.Background())
conn, err = proton.Open(...)

serverGenearatedID, _, err := conn.Query(ctx, "SELECT 123")

For the TestClientGenerateQueryID, I'm not quite sure why I have to pass both proton.WithQueryID(id) and proton.WithReceiveQueryID. I'd expect the client code remains unchanged

@yuzifeng1984
Copy link
Collaborator Author

yuzifeng1984 commented Aug 21, 2024

@yuzifeng1984 I'm purely speaking from the user side (the user of proton-go-driver): The current approach looks weird to me. For the TestServerGenerateQueryID I'd expect something like

ctx = proton.Context(context.Background())
conn, err = proton.Open(...)

serverGenearatedID, _, err := conn.Query(ctx, "SELECT 123")

For the TestClientGenerateQueryID, I'm not quite sure why I have to pass both proton.WithQueryID(id) and proton.WithReceiveQueryID. I'd expect the client code remains unchanged

@ye11ow The unit test case is just for testing purpose.

In real case, user could either give an ID or leave it unset to allow server generate one with the node id in sending query.

  1. When user gives an ID by proton.WithQueryID(id). Proton will not generate one with the node id information. User does not need to set proton.WithReceiveQueryID callback in this case since the same ID will be returned. But the user generated query ID will have the kill-query issue in cluster.

  2. When user does not have proton.WithQueryID(id). Proton will generate the ID. User need to set proton.WithReceiveQueryID to get the server generated ID if user wants to use the ID information for further queries.

@ye11ow
Copy link
Collaborator

ye11ow commented Aug 21, 2024

@yuzifeng1984 I see.
Yeah, I think 1. makes sense.
For two, I got the idea but I think from API design perspective, the WithReceiveQueryID approach is not ideal. This adds quite a few code to client. Just like your example, client needs to be called like this:

idCh = make(chan string, 1)
ctx  = proton.Context(context.Background(), proton.WithReceiveQueryID(func(id string) {
  idCh <- id
  close(idCh)
}))
conn, _ = proton.Open(...)
_, err := conn.Query(ctx, "SELECT 123")
id := <-idCh

// do whatever with id

I'd prefer

ctx  = proton.Context(context.Background())
conn, _ = proton.Open(...)
id, _, err := conn.Query(ctx, "SELECT 123")

// do whatever with id

There are few issues with the current approach

  1. More boilerplate code
  2. I have no idea when WithReceiveQueryID will be called. Is that immediately or after a few seconds? Shall I start the goroutine to read the data and use another goroutine to wait for the ID?

@yuzifeng1984
Copy link
Collaborator Author

yuzifeng1984 commented Aug 21, 2024

@ye11ow Yes. the callback method is a little ugly. While changing Query method interface to return query id seems even worse, it will break every existing user code. Also, as the new signature is not consistent with golang std lib, a lot of under layer code need be changed.

For the callback itself, it will be called synchronously before Query method return. There is some boilerplate code which you may not want to add in neutron. I am thinking if proton-go-driver to provide a new API to wrap these; such as QueryReturnID(context, query) -> (Rows, ID, Error). But you still need to change neutron to call the new method in the places where you want server to generate query ID. What do you think?

@yuzifeng1984
Copy link
Collaborator Author

@ye11ow I checked the neutron code. It looks the query is through the sql.DB in golang lib whose methods can not be changed. We have no choice than the WithReceiveQueryID approach to return the query ID.

https://github.com/timeplus-io/neutron/blob/develop/internal/proton/driver.go#L19

@ye11ow
Copy link
Collaborator

ye11ow commented Aug 27, 2024

@yuzifeng1984 You are right, I almost forgot this: we are using std golang SQL interface so you cannot really change the signature.

Yeah, then we don't even have an option here. Have to go with the WithReceiveQueryID option.

@chenziliang
Copy link
Contributor

chenziliang commented Aug 28, 2024

Is it safe to do following since string is immutable ? my gut feeling is either using ctx or callback for customization. Callback is more straight forward / explicit in my view

var query_id string;

ctx  = proton.Context(context.Background(), proton.WithReceiveQueryID(func(id string) {
    query_id = id;
}))

conn, _ = proton.Open(...)
_, err := conn.Query(ctx, "SELECT 123")

// do whatever query_id

@chenziliang
Copy link
Contributor

is it possible to mutate ctx to carry back the query_id if a callback is not ideal ?

_, err := conn.Query(ctx, "SELECT 123")

@@ -0,0 +1,60 @@
// Licensed to ClickHouse, Inc. under one or more contributor
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't think we need this ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is cherry picked from click house driver to support protocol 54459. since we bump the client protocol to 54461 for uuid.

@yuzifeng1984
Copy link
Collaborator Author

yuzifeng1984 commented Aug 28, 2024

Is it safe to do following since string is immutable ? my gut feeling is either using ctx or callback for customization. Callback is more straight forward / explicit in my view

var query_id string;

ctx  = proton.Context(context.Background(), proton.WithReceiveQueryID(func(id string) {
    query_id = id;
}))

conn, _ = proton.Open(...)
_, err := conn.Query(ctx, "SELECT 123")

// do whatever query_id

@chenziliang @ye11ow
Context is immutable and seems not right way to pass back data. I simplify the test case by directly assigning local string variable since the callback is invoked before Query method return.

https://github.com/timeplus-io/proton-go-driver/pull/70/files#diff-9f2a2381e0cc03e4ae97084cd3fb6b580de684a4e63963f843ff99078e5b5048R14

@chenziliang
Copy link
Contributor

Is it safe to do following since string is immutable ? my gut feeling is either using ctx or callback for customization. Callback is more straight forward / explicit in my view

var query_id string;

ctx  = proton.Context(context.Background(), proton.WithReceiveQueryID(func(id string) {
    query_id = id;
}))

conn, _ = proton.Open(...)
_, err := conn.Query(ctx, "SELECT 123")

// do whatever query_id

@chenziliang @ye11ow Context is immutable and seems not right way to pass back data. I simplify the test case by directly assigning local string variable since the callback is invoked before Query method return.

https://github.com/timeplus-io/proton-go-driver/pull/70/files#diff-9f2a2381e0cc03e4ae97084cd3fb6b580de684a4e63963f843ff99078e5b5048R14

This is much easier and totally makes sense to me

@yuzifeng1984 yuzifeng1984 merged commit 12d13a9 into develop Aug 28, 2024
6 checks passed
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