-
Couldn't load subscription status.
- Fork 5.1k
Update Azure.Core shared for LRO rehydration #41088
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
Conversation
d06f4ab to
9518c51
Compare
|
Can we eliminate some of the shared source files? We consider shared sources to be engineering debt. |
| public override string ToString() { throw null; } | ||
| } | ||
| public abstract partial class Operation | ||
| public partial class Operation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What motivates making this type non-abstract? This is a big change to a central Core type, to it would be good to be crisp on the reasons that motivate this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One suggestion is to add these APIs to an internal subtype of Operation and return that anywhere this instance is needed. I believe we would prefer to keep the Operation type itself internal, as that lets it evolve better in the future, helps us address performance issues, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, did not add enough explanation for this.
The goal is to implement LRO rehydration for both DPG and MPG.
Had a discussion with @m-nash , @KrzysztofCwalina and @tg-msft, given the way we are implementing LRO for DPG nowadays, there is no instantiable type for DPG users, only Operation available.
That's why we want to make Operation non-abstract.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we have two choices: 1) we could make the type non-abstract as in this PR, 2) we could add a static method Operation.Rehydrate that returns an internal subtype of Operation. I know that we initially said that we wanted a ctor, but now that I think about it the static method could be better. Rehydration is an advanced scenario and the static method would hide the API a bit. Also, it would allow us to not have to add fields to Operation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. Static method is better to me as well. Given we can't add type constraint to constructor directly, we need to throw in constructor.
I will create another PR to implement it with static method to not mess with the existing change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created #42686 for static methods
| protected Operation() { } | ||
| public abstract bool HasCompleted { get; } | ||
| public abstract string Id { get; } | ||
| public Operation(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken? rehydrationToken, Azure.Core.ClientOptions options = null) { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be preferable not to add a dependency of an end-user type (Operation) on a client-internal type (HttpPipeline). Is there any way we could avoid this? If you don't know offhand, we might be able to help you find design-alternatives if you could share the scenario that motivates the addition of this API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The actual implementation is hold in NextLinkOperationImplementation, so make Operation non-abstract, we need to implement the LRO rehydration based on NextLinkOperationImplementation.
To be able to construct NextLinkOperationImplementation, we need the user to input HttpPipeline and RehydrationToken, as construction here.
| protected Operation() { } | ||
| public abstract bool HasValue { get; } | ||
| public abstract T Value { get; } | ||
| public Operation(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken? rehydrationToken, Azure.Core.ClientOptions options = null) { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment that we should work to avoid adding a dependency on HttpPipeline in this type's public API.
|
|
||
| if (!lroDetails.TryGetValue("nextRequestUri", out var nextRequestUri)) | ||
| { | ||
| throw new InvalidOperationException("Invalid next request URI from rehydration token"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the correct exception type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update to ArgumentException
| public OperationInternal(IOperation operation, | ||
| ClientDiagnostics clientDiagnostics, | ||
| Response rawResponse, | ||
| Response? rawResponse, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What scenario motivates passing a null raw response? It looks like Operation.GetRawResponse has a non-nullable return type. Are you planning to return null from this method? I believe that would violate the contract with the end user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the case of LRO rehydration used here, the user doesn't have response in place since the operation is not complete.
And if we take a look at the documentation of rawResponse here, it says "When a user instantiates an directly using a public constructor, there's no previous service call. In this case, passing null is expected."
So, I think it should be nullable in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created #42666 for this change.
| } | ||
|
|
||
| public override Response RawResponse => _stateLock.TryGetValue(out var state) ? state.RawResponse : _rawResponse; | ||
| public override Response RawResponse => (_stateLock.TryGetValue(out var state) ? state.RawResponse : _rawResponse) ?? throw new InvalidOperationException("The operation does not have a response yet. Please call UpdateStatus or WaitForCompletion first."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Who calls this API? If it's internal, would it make sense to provide a tester rather than throwing an exception? It is not idiomatic to .NET to throw exceptions from properties - we should avoid doing this if possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The case is, the operation is not complete yet, there is no response for the user to consume.
The user need to update the status till complete firstly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, we should make this nullable instead and check if null in the usage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, we throw on incomplete operation for OperationInternal.Value. To be consistent, we should throw on this as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Get latest state during rehydration to avoid empty raw response, implemented in #42686
| throw state.OperationFailedException!; | ||
| } | ||
|
|
||
| private class EmptyResponse : Response |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, we would avoid adding new internal subtypes of Response. Is there one in the Azure.Core code base you can reuse? If not, it would be good to add a comment to the type to explain why it exists and why it is unique, when you would expect to return it to an end-user, and what they would expect from it, so that maintainers of this code no what they can and can't change going forward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only used for fake delete LRO, we just want to return an empty response with 204 to the user for this case.
Added the above comment to the class documentation. I can't find any existing internal implemented Response type for this usage.
| Assert.Null(operation.GetRehydrationToken()); | ||
| } | ||
|
|
||
| [Test] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we move forward with making the Operation type non-abstract, this test file should contain full coverage of all implementation details of the implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried to add tests for some properties of Operation and OperationOfT.
We need to mock HttpPipeline methods to be able to test UpdateStatus.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be possible with the TestFramework in Azure.Core - let us know if you need any help with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I will dig around firstly, and get back if need any help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented in #42686
|
Based on #41088 (comment), we would like to expose the LRO rehydration functionality as static method, created #42686 for it. |
|
continue the work in #42686 |
RehydrationTokenfrom multiple fieldsOperationLocation,AzureAsyncOperation,LocationorNoneLocationvalue in the response headerAzureAsyncOperation,Location,OriginalUriorOperationLocationOperationnon-abstract