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

[Key Vault Keys] LRO refactoring #11717

Merged
merged 6 commits into from
Nov 17, 2020

Conversation

sadasant
Copy link
Contributor

@sadasant sadasant commented Oct 8, 2020

This PR intends to refactor the Key Vault Keys pollers by:

  • Removing the client and the request options from the operation states.
  • Moving the common properties and methods to specific classes outside of the individual poller files.
  • Moving all of the tracing methods to their own file, independent of the KeyClient class.
  • Removing the pollerClient and re-using the generated KeyVaultClient. The only caveat is that two functions had to be duplicated in the individual poller operation files.

These changes don't represent a behavioral change. It's a refactoring to help us clean up other LROs.

First effort towards: #11698

@sadasant sadasant self-assigned this Oct 8, 2020
@ghost ghost added the KeyVault label Oct 8, 2020
Copy link
Member

@xirzec xirzec left a comment

Choose a reason for hiding this comment

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

Left a few thoughts, I really like the separation of concerns.

cancel,
toString
};
return new DeleteKeyPollOperation(state, this.vaultUrl, this.client, this.requestOptions);
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious, why return a new DeleteKeyPollOperation if the only state inside the object is inside state, but we've been mutating this.state inside this method, since we just assigned it to a local variable without copying it.

It seems like either we shouldn't be mutating state or we shouldn't bother creating a new DeleteKeyPollOperation.

Copy link
Contributor Author

@sadasant sadasant Oct 8, 2020

Choose a reason for hiding this comment

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

I'll update it to return this! Thank you!

We talked about this over private chat and the reason why update expects a return is because of: https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/core/core-lro/src/poller.ts#L316

The current contract of the poller allows for stateless workflows.

I think we made decisions like this in core-lro because of the flexibility they give us. So, no rush on making that contract change, in my opinion!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could do something like: this.operation = update() || this.operation, for example. Even more flexibility! (though the argument that we might not need this much flexibility is valid. I just feel more comfortable making things less restrictive 😅)

Comment on lines +11 to +12
const keyBundle = bundle as KeyBundle;
const deletedKeyBundle = bundle as DeletedKeyBundle;
Copy link
Member

Choose a reason for hiding this comment

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

Feels a little weird to work with the same object in two different variables with two different interfaces.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This transformation was already there, but I agree!

Comment on lines +41 to +52
if (attributes.vaultUrl) {
delete (resultObject.properties as any).vaultUrl;
}
if (attributes.expires) {
delete (resultObject.properties as any).expires;
}
if (attributes.created) {
delete (resultObject.properties as any).created;
}
if (attributes.updated) {
delete (resultObject.properties as any).updated;
}
Copy link
Member

Choose a reason for hiding this comment

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

can we find a way to not spread these onto resultObject in the first place? Even if we have to copy attributes to its own object, delete them, then spread the remainder?

Copy link
Contributor Author

@sadasant sadasant Oct 8, 2020

Choose a reason for hiding this comment

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

I was about to do this, but the context switch is sufficient to give me a headache, since this might have consequences on the public API (hopefully not), so I made an issue instead: #11720

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have an issue to remove all the object spreading on Key Vault: #9730 I'll do it as part of that issue!

sadasant added a commit to sadasant/azure-sdk-for-js that referenced this pull request Oct 8, 2020
@sadasant sadasant marked this pull request as ready for review October 8, 2020 20:26
@sadasant sadasant requested a review from xirzec October 9, 2020 12:20
Copy link
Member

@xirzec xirzec left a comment

Choose a reason for hiding this comment

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

I think I'm happy with this one

sdk/keyvault/keyvault-keys/src/lro/keyVaultKeyPoller.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@willmtemple willmtemple left a comment

Choose a reason for hiding this comment

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

The changes to polling infrastructure look very nice to me. It's definite improvement. Some comments included inline.

* @summary Reaches to the service and updates the delete key's poll operation.
* @param [options] The optional parameters, which are an abortSignal from @azure/abort-controller and a function that triggers the poller's onProgress function.
*/
public async update(
Copy link
Contributor

Choose a reason for hiding this comment

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

This pattern of managing the client seems pretty nice, and definitely less leaky than before. It feels like a good balance between ruthless abstraction and the levels of duplication that we had previously, but it doesn't seem like it's much less verbose than what we had before.

It still feels bizarre to me that we have this state machine model where update can return a different operation, but I can't think of anywhere that we use it. That API suggests to me that returning a different kind of operation should be the way that we make the pollers progress in state, but instead we just have monolithic update functions that handle everything and then return this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I understand how this might be weird! I wonder if it would make sense to open an issue to have a discussion over time of how we could improve this in core-lro 🤔

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I think we should consider if we want this to be stateless or not (no strong feelings from me) and either we lean fully into stateless (get rid of this) or we lean fully away from it (don't bother returning this, because caller already has a copy of us)

* The method used by the poller to wait before attempting to update its operation.
* @memberof DeleteKeyPoller
*/
async delay(): Promise<void> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we provide a default implementation of this method in core-lro? It already depends on core-http, and I'm having a hard time thinking of where anyone would use an implementation other than this in a package, but leaving it open to overrides would still be nice if someone wanted to instrument the delay for some purpose.

Copy link
Contributor Author

@sadasant sadasant Nov 17, 2020

Choose a reason for hiding this comment

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

The issue with this is that we didn't want core-lro to depend on core-http 🤔 and doing an independent delay function seems prone to errors. Would you be on board if I did a default delay method (on core-lro) with a non-core-http delay?

Copy link
Contributor

Choose a reason for hiding this comment

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

core-lro already depends on core-http.

⇒  < ../../core/core-lro/package.json | jq .dependencies
{
  "@azure/abort-controller": "^1.0.0",
  "@azure/core-http": "^1.2.0",
  "events": "^3.0.0",
  "tslib": "^2.0.0"
}

The true problem is that the base Poller doesn't contain a polling interval. If it had one, I think we could just use setTimeout on all targets by default? (CC @xirzec )

For cancellation we would just have to store the timer ID and handle it when the operation is cancelled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

stopping the poller and cancelling the operation is different! but I see what you mean. I'll make an issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I made an issue! #12583

Copy link
Member

Choose a reason for hiding this comment

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

Having some kind of default delay implementation makes sense to me.

@sadasant sadasant merged commit 1605209 into Azure:master Nov 17, 2020
@sadasant sadasant deleted the keyvault-keys/lro-refactoring-11698 branch November 17, 2020 22:14
openapi-sdkautomation bot pushed a commit to AzureSDKAutomation/azure-sdk-for-js that referenced this pull request Nov 19, 2020
Specifying shipping address required property to autorest. (Azure#11717)

* Ensuring autorest generation follow specific order of required properties in shippingAddress

* added details  sharp yaml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants