azure-sdk-for-js icon indicating copy to clipboard operation
azure-sdk-for-js copied to clipboard

Decide on versioning policy when switching to core-rest-pipeline

Open maorleger opened this issue 4 years ago • 24 comments

Came up in a discussion: does switching a GA package to corev2 warrant a major or minor version bump?

Some more details from @xirzec below:

There are 3 relatively minor breaking changes:

  • Optional property mode was removed from retryOptions since it only ever had a single enum value and was never used.
  • handleRedirects was removed from redirectOptions, as the policy can now be controlled by removing it from the pipeline or setting maxRedirects to 0.
  • keepAliveOptions were removed. Keep alive can be disabled on a per-request basis with disableKeepAlive.

These were all fairly niche options that tended to be used internally by our clients rather than set by consumers, but since we did expose them, we should consider what versioning implication this poses.

Alongside the change to remove _response, a strict semver interpretation would be to major version the package, but debatably a minor bump could be sufficient. /cc @chradek @ramya-rao-a @jeremymeng - I think we should have broad agreement on what our policy is here.

Originally posted by @xirzec in https://github.com/Azure/azure-sdk-for-js/pull/15881#discussion_r656365233

maorleger avatar Jun 23 '21 03:06 maorleger

One determinant could be if any of these options/properties show up in existing README snippets or samples. If not, I think we could argue a minor bump is sufficient.

xirzec avatar Jun 24 '21 18:06 xirzec

Yes it's unlikely that customers use these options directly. Minor bump is fine.

jeremymeng avatar Jun 25 '21 17:06 jeremymeng

I feel like the _response change by itself is enough to necessitate the major version bump unless you never exposed it for this particular package. The optional parameters going away could cause compile-time issues if customers are in-lining their options and were previously specifying those parameters, and the disableKeepAlive no longer being honored would be very frustrating if you were a customer that decided they did want to disable it.

Anyway, my vote would be to respect semver and do a major version bump.

chradek avatar Jun 25 '21 17:06 chradek

cc @sarangan12 and @witemple-msft as we were talking about the same recently

ramya-rao-a avatar Aug 04 '21 18:08 ramya-rao-a

I'm a fan of pedantic semver fwiw. We shouldn't break people and can message it as such. That said, there may be downsides I'm not considering - would be good to surface those more explicitly.

bterlson avatar Aug 04 '21 19:08 bterlson

The only downside of being pedantic in this case appears to be policy around supporting major versions for an extra year, so we'd increase our dev costs each time we did it.

xirzec avatar Aug 04 '21 20:08 xirzec

My 2 cents: The _response removal should be a major version bump. It could cause overhead for us. But, we could protect customers from unwanted surprises and that should take priority

sarangan12 avatar Aug 04 '21 23:08 sarangan12

Seems like we have consensus. One question though: does the answer change if the sdk in question did work to not expose _response, as ACS did?

xirzec avatar Aug 05 '21 04:08 xirzec

If the SDK has done work to intentionally not expose _response, then the migration cannot be considered a breaking change solely based on the removal of _response. (But, if there is some other change that might cause a breaking change, that would be a different story)

sarangan12 avatar Aug 05 '21 05:08 sarangan12

For packages that did expose _response, can we have something in the convenience layer to use the new callback and continue to support the _response?

ramya-rao-a avatar Aug 18 '21 17:08 ramya-rao-a

We will experiment with supporting compatibility for existing GA'd packages. Starting with KV Admin, which is already migrated over, GA'd, and is currently in beta for the next version, I will try creating a PR preserving compatibility for the October milestone

maorleger avatar Aug 18 '21 18:08 maorleger

Summary of our discussion (CC @maorleger)

For _response, we can instrument the convenience layer to retrieve requests with onResponse:

  • need to preserve the user's onResponse handler if it is set
  • only applies to packages that exposed _response in the public API surface.

For removed options, ingest them into the convenience layer request options:

  • Deprecate retryOptions.mode, has no effect
  • redirectOptions.handleRedirects
    • false => maxRedirects: 0
    • true => maxRedirects: undefined
    • (what do you do if maxRedirects is also specified? Maybe we can throw an Error?)
  • keepAliveOptions.enabled
    • false => disableKeepAlive: true
    • true => do nothing

willmtemple avatar Aug 18 '21 18:08 willmtemple

what do you do if maxRedirects is also specified? Maybe we can throw an Error

We can document the older option as being kept for backward compat and point folks to the new one. If both are set to conflicting values, I am fine throwing an error asking them to choose 1.

ramya-rao-a avatar Aug 18 '21 19:08 ramya-rao-a

Since core-http works on WebResourceLikes and core-rest-pipeline works on PipelineRequests, there are some differences:

export interface WebResourceLike {
    // shared members are omitted
    clone(): WebResourceLike; //removed
    decompressResponse?: boolean; // removed
    headers: HttpHeadersLike; // some small differences in this shape
    keepAlive?: boolean; // renamed to disableKeepAlive and flipped
    prepare(options: RequestPrepareOptions): WebResourceLike; //removed
    query?: { // removed, part of URL
        [key: string]: any;
    };
    spanOptions?: SpanOptions; // inside OperationTracingOptions
    // @deprecated (undocumented)
    streamResponseBody?: boolean; // removed, since deprecated
    tracingContext?: Context; // inside OperationTracingOptions
    validateRequestProperties(): void; // removed
}

clone is the worst one, since implementing it actually breaks the way the new pipeline model works, since requests are expected to have a durable object identity

xirzec avatar Aug 18 '21 20:08 xirzec

what do you do if maxRedirects is also specified? Maybe we can throw an Error

We can document the older option as being kept for backward compat and point folks to the new one. If both are set to conflicting values, I am fine throwing an error asking them to choose 1.

You can set maxRedirects to something positive and handleRedirects to false today, but effectively that's the same as setting maxRedirects to 0 again as maxRedirects won't be consulted in that case. I don't think we should throw an error for an edge case we didn't validate previously.

xirzec avatar Aug 18 '21 20:08 xirzec

Since core-http works on WebResourceLikes and core-rest-pipeline works on PipelineRequests, there are some differences:


export interface WebResourceLike {

    // shared members are omitted

    clone(): WebResourceLike; //removed

    decompressResponse?: boolean; // removed

    headers: HttpHeadersLike; // some small differences in this shape

    keepAlive?: boolean; // renamed to disableKeepAlive and flipped

    prepare(options: RequestPrepareOptions): WebResourceLike; //removed

    query?: { // removed, part of URL

        [key: string]: any;

    };

    spanOptions?: SpanOptions; // inside OperationTracingOptions

    // @deprecated (undocumented)

    streamResponseBody?: boolean; // removed, since deprecated

    tracingContext?: Context; // inside OperationTracingOptions

    validateRequestProperties(): void; // removed

}

clone is the worst one, since implementing it actually breaks the way the new pipeline model works, since requests are expected to have a durable object identity

You know, for all the topics we discussed today about the options types, we glossed over HttpClient itself. It will be difficult to reconcile this in a non-breaking way.

Do you think it's possible to project a PipelineRequest into an interface that is API compatible with WebResourceLike? All optional fields that were removed, we could provide undefined.

For the clone() method, is the assumption of object identity because the pipeline stores a ref to the request and assumes it is the same one that is ultimately passed to a transport?

willmtemple avatar Aug 18 '21 21:08 willmtemple

Storage disables decompression in NodeJS. Could it be achieved by not adding decompression policy into the pipeline?

jeremymeng avatar Aug 18 '21 22:08 jeremymeng

For the clone() method, is the assumption of object identity because the pipeline stores a ref to the request and assumes it is the same one that is ultimately passed to a transport?

Nah, it's because core-client uses object identity to associate the request with ServiceClient specific metadata (i.e. OperationSpec and friends) rather than setting these directly on the request object (and requiring clone to be aware of how to copy these properties)

xirzec avatar Aug 19 '21 18:08 xirzec

Storage disables decompression in NodeJS. Could it be achieved by not adding decompression policy into the pipeline?

Yeah they can just remove the policy from the pipeline (or create their own pipeline without it.)

xirzec avatar Aug 19 '21 18:08 xirzec

I guess the only way this really gets leaked from the Form Recognizer client is through the httpClient constructor option. To be able to support this we'd need to be able to convert:

  • PipelineRequest -> WebResourceLike (but I don't think it really matters if clone adheres to the object identity rules of the pipeline, since the HttpClient is the last step in the pipeline)
  • HttpOperationResponse -> PipelineResponse

Basically the question is whether we can project a core-http transport policy into a core-rest-pipeline HttpClient.

willmtemple avatar Aug 20 '21 02:08 willmtemple

I haven't caught up with the conversations yet but as far as delivering on this experiment I probably don't have the bandwidth to take in all the increased scope here...

I am happy to pair or divide-and-conquer with @willmtemple or @xirzec on the rest but I really can only commit to the original scope given other priorities. We should decide what's the best way to get this resolved by the October milestone though if possible - I'll reach out offline

maorleger avatar Sep 02 '21 23:09 maorleger

@sarangan12 is planning to make the move to core-rest-pipeline in the search package that he owns. He will be taking over the investigations here

ramya-rao-a avatar Sep 09 '21 21:09 ramya-rao-a

I have completed the migration for search-documents SDK and documented the steps at the wiki

I do not see any breaking changes except for handling of the _response in the search-documents SDK. Even if other SDKs could possibly have some breaking changes (we could determine it only on case by case basis), they could be handled in the custom layer.

sarangan12 avatar Oct 01 '21 21:10 sarangan12

Another potential breaking change might be that

FullOperationResponse is not 100% compatible with HttpOperationResponse. For example, the http headers type is different. We may have to re-define.

From https://github.com/Azure/azure-sdk-for-js/pull/18736#discussion_r755370326

maorleger avatar Nov 29 '21 17:11 maorleger