-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[core-http] Throttling retry policy fix in core-http #15832
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
Merged
Merged
Changes from 10 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
0616843
throttling policy fix in core-http
HarshaNalluru 10a3816
remove comment
HarshaNalluru 8bf61fe
typo
HarshaNalluru d876b54
import core-amqp delay from core-util
HarshaNalluru db74514
import core-util
HarshaNalluru 01bd7c4
Merge branch 'master' of https://github.com/Azure/azure-sdk-for-js in…
HarshaNalluru a0307af
import { delay } from "@azure/core-util";
HarshaNalluru 78814aa
changelog
HarshaNalluru ff9cb2a
throw abort error check
HarshaNalluru d003ea8
revert core-rest-pipeline
HarshaNalluru 15f9428
Merge branch 'main' of https://github.com/Azure/azure-sdk-for-js into…
HarshaNalluru c774368
import { delay } from "@azure/core-util";
HarshaNalluru daedfbb
fix linter errors
HarshaNalluru 0dd2974
fix build failures
HarshaNalluru 6c4ed84
export { delay } from "@azure/core-util";
HarshaNalluru 0ad0a26
API Report
HarshaNalluru f7e294a
Merge branch 'main' of https://github.com/Azure/azure-sdk-for-js into…
HarshaNalluru d80e0d9
Merge branch 'main' of https://github.com/Azure/azure-sdk-for-js into…
HarshaNalluru 97c6f0a
have 2 copies of delay
HarshaNalluru 99f4d41
keep duplicates
HarshaNalluru 8d77016
API Report
HarshaNalluru ed5e621
retain core-util
HarshaNalluru 8977a42
get rid of circular dependencies
HarshaNalluru 3029418
value should be the second argument
HarshaNalluru 75ad58e
update delay to have options bag and additional feedback
HarshaNalluru 6ede956
make async functions and typeguard feedback
HarshaNalluru 37018a1
update app-config and API Report
HarshaNalluru 1a6555b
HttpMockFacade
HarshaNalluru 58b5855
should honor the abort signal passed
HarshaNalluru a3a0a04
remove nock
HarshaNalluru 9b7f233
satisfy linter
HarshaNalluru File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT license. | ||
|
|
||
| import { AbortError, AbortSignalLike } from "@azure/abort-controller"; | ||
| import { AbortError } from "@azure/abort-controller"; | ||
| import { | ||
| BaseRequestPolicy, | ||
| RequestPolicy, | ||
|
|
@@ -12,7 +12,7 @@ import { | |
| Constants, | ||
| RestError | ||
| } from "@azure/core-http"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now we just need to move to corev2 so we can fix #6484 |
||
| import { isDefined } from "../internal/typeguards"; | ||
| import { delay } from "@azure/core-util"; | ||
|
|
||
| /** | ||
| * @internal | ||
|
|
@@ -27,55 +27,6 @@ export function throttlingRetryPolicy(): RequestPolicyFactory { | |
|
|
||
| const StandardAbortMessage = "The operation was aborted."; | ||
|
|
||
| /** | ||
| * A wrapper for setTimeout that resolves a promise after t milliseconds. | ||
| * @param delayInMs - The number of milliseconds to be delayed. | ||
| * @param abortSignal - The abortSignal associated with containing operation. | ||
| * @param abortErrorMsg - The abort error message associated with containing operation. | ||
| * @returns - Resolved promise | ||
| */ | ||
| export function delay( | ||
| delayInMs: number, | ||
| abortSignal?: AbortSignalLike, | ||
| abortErrorMsg?: string | ||
| ): Promise<void> { | ||
| return new Promise((resolve, reject) => { | ||
| let timer: ReturnType<typeof setTimeout> | undefined = undefined; | ||
| let onAborted: (() => void) | undefined = undefined; | ||
|
|
||
| const rejectOnAbort = (): void => { | ||
| return reject(new AbortError(abortErrorMsg ? abortErrorMsg : StandardAbortMessage)); | ||
| }; | ||
|
|
||
| const removeListeners = (): void => { | ||
| if (abortSignal && onAborted) { | ||
| abortSignal.removeEventListener("abort", onAborted); | ||
| } | ||
| }; | ||
|
|
||
| onAborted = (): void => { | ||
| if (isDefined(timer)) { | ||
| clearTimeout(timer); | ||
| } | ||
| removeListeners(); | ||
| return rejectOnAbort(); | ||
| }; | ||
|
|
||
| if (abortSignal && abortSignal.aborted) { | ||
| return rejectOnAbort(); | ||
| } | ||
|
|
||
| timer = setTimeout(() => { | ||
| removeListeners(); | ||
| resolve(); | ||
| }, delayInMs); | ||
|
|
||
| if (abortSignal) { | ||
| abortSignal.addEventListener("abort", onAborted); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * This policy is a close copy of the ThrottlingRetryPolicy class from | ||
| * core-http with modifications to work with how AppConfig is currently | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
sdk/core/core-http/test/policies/throttlingRetryPolicy.node.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import nock from "nock"; | ||
jeremymeng marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| import { Constants, ServiceClient } from "../../src/coreHttp"; | ||
| import { AbortController } from "@azure/abort-controller"; | ||
| import { assert } from "chai"; | ||
|
|
||
| describe("Throttling retry policy", () => { | ||
| let client: ServiceClient; | ||
|
|
||
| beforeEach(function() { | ||
| if (!nock.isActive()) { | ||
| nock.activate(); | ||
| } | ||
| nock("https://fakeservice.io:443") | ||
| .persist() | ||
| .put(/.*/g) | ||
| .reply( | ||
| Constants.HttpConstants.StatusCodes.TooManyRequests, | ||
| { | ||
| type: "https://fakeservice.io/errors/too-many-requests", | ||
| title: "Resource utilization has surpassed the assigned quota", | ||
| policy: "Total Requests", | ||
| status: Constants.HttpConstants.StatusCodes.TooManyRequests | ||
| }, | ||
| ["Retry-After", "10000"] | ||
| ); | ||
| client = new ServiceClient(); | ||
| }); | ||
|
|
||
| afterEach(async function() { | ||
| nock.restore(); | ||
| nock.cleanAll(); | ||
| nock.enableNetConnect(); | ||
| }); | ||
|
|
||
| it("Should not retry forever (honors the abort signal passed)", async () => { | ||
| let errorWasThrown = false; | ||
| try { | ||
| await client.sendRequest({ | ||
| url: "https://fakeservice.io/ABCD", | ||
| abortSignal: AbortController.timeout(100), | ||
| method: "PUT" | ||
| }); | ||
| } catch (error) { | ||
| errorWasThrown = true; | ||
| assert.equal((error as any).name, "AbortError", "Unexpected error thrown"); | ||
| } | ||
| assert.equal(errorWasThrown, true, "Error was not thrown"); | ||
| }); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,57 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT license. | ||
|
|
||
| import { isDefined } from "./typeguards"; | ||
| import { AbortError, AbortSignalLike } from "@azure/abort-controller"; | ||
| const StandardAbortMessage = "The operation was aborted."; | ||
|
|
||
| /** | ||
| * A wrapper for setTimeout that resolves a promise after timeInMs milliseconds. | ||
| * @param timeInMs - The number of milliseconds to be delayed. | ||
| * @returns Promise that is resolved after timeInMs | ||
| * A wrapper for setTimeout that resolves a promise after delayInMs milliseconds. | ||
| * @param delayInMs - The number of milliseconds to be delayed. | ||
| * @param abortSignal - The abortSignal associated with containing operation. | ||
| * @param abortErrorMsg - The abort error message associated with containing operation. | ||
| * @param value - The value to be resolved with after a timeout of t milliseconds. | ||
| * @returns - Resolved promise | ||
| */ | ||
| export function delay(timeInMs: number): Promise<void> { | ||
| return new Promise((resolve) => setTimeout(() => resolve(), timeInMs)); | ||
| export function delay<T>( | ||
| delayInMs: number, | ||
| abortSignal?: AbortSignalLike, | ||
| abortErrorMsg?: string, | ||
| value?: T | ||
| ): Promise<T | void> { | ||
| return new Promise((resolve, reject) => { | ||
| let timer: ReturnType<typeof setTimeout> | undefined = undefined; | ||
| let onAborted: (() => void) | undefined = undefined; | ||
|
|
||
| const rejectOnAbort = (): void => { | ||
| return reject(new AbortError(abortErrorMsg ? abortErrorMsg : StandardAbortMessage)); | ||
| }; | ||
|
|
||
| const removeListeners = (): void => { | ||
| if (abortSignal && onAborted) { | ||
| abortSignal.removeEventListener("abort", onAborted); | ||
| } | ||
| }; | ||
|
|
||
| onAborted = (): void => { | ||
| if (isDefined(timer)) { | ||
| clearTimeout(timer); | ||
| } | ||
| removeListeners(); | ||
| return rejectOnAbort(); | ||
| }; | ||
|
|
||
| if (abortSignal && abortSignal.aborted) { | ||
| return rejectOnAbort(); | ||
| } | ||
|
|
||
| timer = setTimeout(() => { | ||
| removeListeners(); | ||
| resolve(value); | ||
| }, delayInMs); | ||
|
|
||
| if (abortSignal) { | ||
| abortSignal.addEventListener("abort", onAborted); | ||
| } | ||
| }); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT license. | ||
|
|
||
| /** | ||
| * Helper TypeGuard that checks if something is defined or not. | ||
| * @param thing - Anything | ||
| * @internal | ||
| */ | ||
| export function isDefined<T>(thing: T | undefined | null): thing is T { | ||
| return typeof thing !== "undefined" && thing !== null; | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 appconfiguration in beta? if not, it should not take a dep on a beta.
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.
App-config is beta, but we may soon GA in the next couple of months.
Why is core-util in beta anyways? Can't we make that GA instead?
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.
Because we did not settle on the public surface for it yet.
appconfig is in beta but core-http and core-amqp are not IIRC and you added core-util as a dep there. My recommendation is to keep the local implementation of delay for now and have it moved to core-util in another PR.
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 really don't want to keep 3 copies of delay (core-http, core-amqp and app-config).
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.
@jeremymeng @chradek @richardpark-msft
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.
Why cannot App Config use the one in core-http?
Since this PR's main objective is around fixing an issue with the retry policy, can we stick to just that in this PR?
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.
@ramya-rao-a So, you're suggesting core-http and core-amqp would have delay? Can do that if weare fine with 2 copies.
(What's the point of core-util then?)
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.
#15930
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 is pending the on the conclusion on the discussion we had today on the subject of code sharing
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.
We now have two copies of (advanced) delay.. core-amqp and core-http.
Logged #15930 for core-util discussion.