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

server: fix ChainUnaryInterceptor and ChainStreamInterceptor to allow retrying handlers #5666

Merged
merged 3 commits into from Nov 22, 2022

Conversation

yiminc
Copy link
Contributor

@yiminc yiminc commented Sep 23, 2022

Make it possible to retry UnaryServerInterceptor in chained UnaryInterceptors.

RELEASE NOTES:

  • server: fix ChainUnaryInterceptor and ChainStreamInterceptor to allow retrying handlers

@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented Sep 23, 2022

CLA Signed

The committers listed above are authorized under a signed CLA.

  • ✅ login: yiminc / name: Yimin Chen (1d05928)

@dfawley dfawley added this to the 1.51 Release milestone Oct 4, 2022
@easwars
Copy link
Contributor

easwars commented Oct 4, 2022

Could you please tell us what these changes are meant for? It is not clear from reading the changes in the PR.

@github-actions
Copy link

This PR is labeled as requiring an update from the reporter, and no update has been received after 6 days. If no update is provided in the next 7 days, this issue will be automatically closed.

@github-actions github-actions bot added the stale label Oct 10, 2022
@yiminc
Copy link
Contributor Author

yiminc commented Oct 11, 2022

If you have one interceptor in a chained interceptors that has retry logic, it will skip all subsequent interceptors. See the added unit test, if the interceptor i1 has retry logic when it sees retry-able error, the retry will skip interceptor i2 without this fix.

@github-actions github-actions bot removed the stale label Oct 11, 2022
@easwars
Copy link
Contributor

easwars commented Oct 11, 2022

If you have one interceptor in a chained interceptors that has retry logic

What do you mean by retry logic? How do we know if an interceptor has retry logic?

I'm not being rude here. But I don't think this change makes any sense. If you are interesting in adding functionality like this, please open an issue and have a discussion with us before sending us a PR.

@easwars easwars closed this Oct 11, 2022
@yiminc
Copy link
Contributor Author

yiminc commented Oct 12, 2022

You could have a generic interceptor that does automatic retry on some errors like:

func RetryIntercept(
	ctx context.Context,
	req interface{},
	info *grpc.UnaryServerInfo,
	handler grpc.UnaryHandler,
) (interface{}, error) {
	var response interface{}
	op := func(ctx context.Context) error {
		var err error
		response, err = handler(ctx, req) // When this is called by retry, it skips subsequent interceptors.
		return err
	}

	err := backoff.RetryWithContext(ctx, op, retryPolicy)
	return response, err
}

Then you chain this interceptor with your other interceptors:
chainedInterceptor := grpc.ChainUnaryInterceptor(RetryIntercept, fooIntercept, barIntercept)
And you use chainedInterceptor as the final interceptor, when handler(ctx, req) is called for retry by RetryIntercept, the fooIntercept will be skipped. This is a problem if fooIntercept setup something in the context that barIntercept expect, barIntercept will fail to find that value from context.

@easwars

@dfawley
Copy link
Member

dfawley commented Oct 17, 2022

Can you explain why you're retrying on a server? I can understand retrying on the client, but how and why would you retry on a server?

@dfawley dfawley reopened this Oct 17, 2022
@github-actions
Copy link

This PR is labeled as requiring an update from the reporter, and no update has been received after 6 days. If no update is provided in the next 7 days, this issue will be automatically closed.

@github-actions github-actions bot added the stale label Oct 23, 2022
@yiminc
Copy link
Contributor Author

yiminc commented Oct 27, 2022

This could be used as a generic way to retry all APIs on specific error types. So instead of having retry logic all over the places, we could have one interceptor that do the generic retry.
The current behavior is surprising because it skips some interceptors and caused unexpected results.

@easwars
Copy link
Contributor

easwars commented Nov 1, 2022

I looked at how interceptors are chained on the client. See: https://github.com/grpc/grpc-go/blob/fdcc01b8c12bf76885cfe93e2c3dd6080a655d81/clientconn.go#L335:6. This sets the invoker to getChainUnaryInvoker which uses a recursive logic to run the next interceptor in the chain.

The chaining logic on the server does not use a recursive mechanism, but keeps some local state which is modified as part of the execution of every interceptor in the chain. And this is the reason why retrying on the server side does not work as expected (although we still don't understand when and where retrying on the server would be helpful).

We discussed this, and we think that changing the server implementation to mimic the client implementation would be better fix. Would you be interested in making that change?

@yiminc
Copy link
Contributor Author

yiminc commented Nov 5, 2022

@easwars thanks for spending time on this. Yes, the bug was because the server side logic uses that local variable. The fix is to properly decrement after each invocation. This mimic the behavior of a recursive behavior.
I have updated the PR to use a regular recursive instead.

server_test.go Outdated Show resolved Hide resolved
server.go Show resolved Hide resolved
@easwars easwars assigned dfawley and unassigned easwars Nov 15, 2022
@easwars
Copy link
Contributor

easwars commented Nov 15, 2022

@dfawley : For second set of eyes.

@dfawley dfawley changed the title Fix chainUnaryInterceptors to allow retry server: fix ChainUnaryInterceptor and ChainStreamInterceptor to allow retrying handlers Nov 22, 2022
@dfawley dfawley merged commit adfb915 into grpc:master Nov 22, 2022
1 check passed
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 22, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants