-
Notifications
You must be signed in to change notification settings - Fork 12
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
issue: atypical client creation #45
Comments
Can you clarify what you want these classes to look like? Is the problem that the method is not named |
I'm not doing that. It makes debugging this code so confusing (source: I've tried to debug issues with the python client library in the past). Composition is much more understandable than inheritance/decoration. I've created #54 demonstrating what the publisher client would look like, but I don't think this necessarily provides any value (its effectively a settings holder with no behavior). If this is preferable though I can make the equivalent change for the subscribe side. |
I don't want to mix the interface and the code. I can implement a wrapper class distinct from the interface that looks like the generated client, but I'm not going to put AdminClientImpl there. |
Even #54 is odd because one has to call |
Publisher needs to be a context manager to clean up the associated stream and thread resources. If there is a different pattern for resource cleanup that is preferred I can use that instead, but context managers are AFAIK the blessed way to do this in python. |
In the BigQuery Storage API, we need to wrap the generated clients too. We subclass them here: This makes sure our constructor has the same pattern as all the other Google Cloud client libraries. |
Currently client objects (be they handwritten or generated) are consistently imported as something similar to @dpcollins-google There is some proposed work to allow client objects to behave as context managers. googleapis/gapic-generator-python#575 You could possibly use a similar implementation for Publisher. |
I do not want to subclass them. The constructor can have the same call pattern without subclassing, but if we were to subclass, we would add methods just to then remove them (by overwriting them with methods of the same name, which would have to be done for every method)
The problem is that the client would then have to be split between sync and async to be usable as both a sync and async context manager, and managing the lifetime of multiple single-topic streams, meaning it would lose the "client fails permanently on permanent errors" aspect. If this is the way we want to go, it would make both the publisher and subscriber client more similar to CPS, and I could split it into sync and async versions, but it would add significant implementation complexity. I will provide an example of how this would look (with tests to be added later) |
Look at #56, thoughts? |
#56 is much closer to the user experience with Pub/Sub. I left some comments. I'm less concerned about inefficiencies in the inheritance pattern than "client fails permanently on permanent errors". Can you describe what that means in an example? It looks like Pub/Sub uses both sync and async clients too. |
This is no longer the case with the multiplexed clients, which is part of why I wanted to avoid this. Essentially: when you publish or subscribe, any retryable errors are retried, and the Subscriber or Publisher objects become unusable due to the non-retryable error. This is no longer the case with #56, as it will recreate failed clients for new operations. However, those new clients are just as likely to fail, as the previous publish client (for example) would ONLY have failed on something like INVALID_ARGUMENT or FAILED_PRECONDITION. The user is no longer forced to handle this error, but can treat it as a normal singleton RPC failure and retry the future in userland. The previous construction intentionally makes this pattern difficult, as the next stream will almost certainly also fail with the same error. |
With #56, only non-retryable errors would surface to the client and fail the future, right? Retryable errors would be retried silently. Is this really such a big behavioral difference? |
Current:
Expected:
The text was updated successfully, but these errors were encountered: