Skip to content

Commit

Permalink
Update the core-lro to v3 preview version
Browse files Browse the repository at this point in the history
  • Loading branch information
Chung Sheng Fu authored and Chung Sheng Fu committed May 22, 2024
1 parent 3354597 commit 7ac973d
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 11 deletions.
4 changes: 2 additions & 2 deletions sdk/face/ai-vision-face-rest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@
"@azure/core-rest-pipeline": "^1.5.0",
"@azure/logger": "^1.0.0",
"tslib": "^2.6.2",
"@azure/core-lro": "^2.5.4",
"@azure/abort-controller": "^1.0.0"
"@azure/core-lro": "3.0.0-beta.1",
"@azure/abort-controller": "^2.0.0"
},
"devDependencies": {
"dotenv": "^16.0.0",
Expand Down
24 changes: 23 additions & 1 deletion sdk/face/ai-vision-face-rest/review/ai-vision-face.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

/// <reference types="node" />

import { AbortSignalLike } from '@azure/abort-controller';
import { CancelOnProgress } from '@azure/core-lro';
import { Client } from '@azure-rest/core-client';
import { ClientOptions } from '@azure-rest/core-client';
import { CreateHttpPollerOptions } from '@azure/core-lro';
Expand All @@ -14,7 +16,6 @@ import { KeyCredential } from '@azure/core-auth';
import { OperationState } from '@azure/core-lro';
import { RawHttpHeaders } from '@azure/core-rest-pipeline';
import { RequestParameters } from '@azure-rest/core-client';
import { SimplePollerLike } from '@azure/core-lro';
import { StreamableMethod } from '@azure-rest/core-client';
import { TokenCredential } from '@azure/core-auth';

Expand Down Expand Up @@ -4050,6 +4051,27 @@ export interface Routes {
(path: "/detectLivenessWithVerify/singleModal/sessions/{sessionId}/audit", sessionId: string): GetLivenessWithVerifySessionAuditEntries;
}

// @public
export interface SimplePollerLike<TState extends OperationState<TResult>, TResult> {
getOperationState(): TState;
getResult(): TResult | undefined;
isDone(): boolean;
isStopped(): boolean;
onProgress(callback: (state: TState) => void): CancelOnProgress;
poll(options?: {
abortSignal?: AbortSignalLike;
}): Promise<TState>;
pollUntilDone(pollOptions?: {
abortSignal?: AbortSignalLike;
}): Promise<TResult>;
serialize(): Promise<string>;
// @deprecated
stopPolling(): void;
submitted(): Promise<void>;
// @deprecated
toString(): string;
}

// @public
export interface TrainingResultOutput {
createdDateTime: string;
Expand Down
140 changes: 132 additions & 8 deletions sdk/face/ai-vision-face-rest/src/pollingHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
// Licensed under the MIT license.

import { Client, HttpResponse } from "@azure-rest/core-client";
import { AbortSignalLike } from "@azure/abort-controller";
import {
CancelOnProgress,
CreateHttpPollerOptions,
LongRunningOperation,
LroResponse,
OperationResponse,
OperationState,
SimplePollerLike,
createHttpPoller,
} from "@azure/core-lro";
import {
Expand Down Expand Up @@ -42,6 +43,71 @@ import {
UpdateDynamicPersonGroupWithPersonChangesDefaultResponse,
UpdateDynamicPersonGroupWithPersonChangesLogicalResponse,
} from "./responses.js";

/**
* A simple poller that can be used to poll a long running operation.
*/
export interface SimplePollerLike<TState extends OperationState<TResult>, TResult> {
/**
* Returns true if the poller has finished polling.
*/
isDone(): boolean;
/**
* Returns true if the poller is stopped.
*/
isStopped(): boolean;
/**
* Returns the state of the operation.
*/
getOperationState(): TState;
/**
* Returns the result value of the operation,
* regardless of the state of the poller.
* It can return undefined or an incomplete form of the final TResult value
* depending on the implementation.
*/
getResult(): TResult | undefined;
/**
* Returns a promise that will resolve once a single polling request finishes.
* It does this by calling the update method of the Poller's operation.
*/
poll(options?: { abortSignal?: AbortSignalLike }): Promise<TState>;
/**
* Returns a promise that will resolve once the underlying operation is completed.
*/
pollUntilDone(pollOptions?: { abortSignal?: AbortSignalLike }): Promise<TResult>;
/**
* Invokes the provided callback after each polling is completed,
* sending the current state of the poller's operation.
*
* It returns a method that can be used to stop receiving updates on the given callback function.
*/
onProgress(callback: (state: TState) => void): CancelOnProgress;

/**
* Returns a promise that could be used for serialized version of the poller's operation
* by invoking the operation's serialize method.
*/
serialize(): Promise<string>;

/**
* Wait the poller to be submitted.
*/
submitted(): Promise<void>;

/**
* Returns a string representation of the poller's operation. Similar to serialize but returns a string.
* @deprecated Use serialize() instead.
*/
toString(): string;

/**
* Stops the poller from continuing to poll. Please note this will only stop the client-side polling
* @deprecated Use abortSignal to stop polling instead.
*/
stopPolling(): void;
}

/**
* Helper function that builds a Poller object to help polling a long running operation.
* @param client - Client to use for sending the request to get additional pages.
Expand Down Expand Up @@ -132,37 +198,95 @@ export async function getLongRunningPoller<TResult extends HttpResponse>(
initialResponse: TResult,
options: CreateHttpPollerOptions<TResult, OperationState<TResult>> = {},
): Promise<SimplePollerLike<OperationState<TResult>, TResult>> {
const abortController = new AbortController();
const poller: LongRunningOperation<TResult> = {
requestMethod: initialResponse.request.method,
requestPath: initialResponse.request.url,
sendInitialRequest: async () => {
// In the case of Rest Clients we are building the LRO poller object from a response that's the reason
// we are not triggering the initial request here, just extracting the information from the
// response we were provided.
return getLroResponse(initialResponse);
},
sendPollRequest: async (path) => {
sendPollRequest: async (path, sendPollRequestOptions?: { abortSignal?: AbortSignalLike }) => {
// This is the callback that is going to be called to poll the service
// to get the latest status. We use the client provided and the polling path
// which is an opaque URL provided by caller, the service sends this in one of the following headers: operation-location, azure-asyncoperation or location
// depending on the lro pattern that the service implements. If non is provided we default to the initial path.
const response = await client.pathUnchecked(path ?? initialResponse.request.url).get();
function abortListener(): void {
abortController.abort();
}
const inputAbortSignal = sendPollRequestOptions?.abortSignal;
const abortSignal = abortController.signal;
if (inputAbortSignal?.aborted) {
abortController.abort();
} else if (!abortSignal.aborted) {
inputAbortSignal?.addEventListener("abort", abortListener, {
once: true,
});
}
let response;
try {
response = await client
.pathUnchecked(path ?? initialResponse.request.url)
.get({ abortSignal });
} finally {
inputAbortSignal?.removeEventListener("abort", abortListener);
}
const lroResponse = getLroResponse(response as TResult);
lroResponse.rawResponse.headers["x-ms-original-url"] = initialResponse.request.url;
return lroResponse;
},
};

options.resolveOnUnsuccessful = options.resolveOnUnsuccessful ?? true;
return createHttpPoller(poller, options);
const httpPoller = createHttpPoller(poller, options);
const simplePoller: SimplePollerLike<OperationState<TResult>, TResult> = {
isDone() {
return httpPoller.isDone;
},
isStopped() {
return httpPoller.isStopped;
},
getOperationState() {
if (!httpPoller.operationState) {
throw new Error(
"Operation state is not available. The poller may not have been started and you could await submitted() before calling getOperationState().",
);
}
return httpPoller.operationState;
},
getResult() {
return httpPoller.result;
},
toString() {
if (!httpPoller.operationState) {
throw new Error(
"Operation state is not available. The poller may not have been started and you could await submitted() before calling getOperationState().",
);
}
return JSON.stringify({
state: httpPoller.operationState,
});
},
stopPolling() {
abortController.abort();
},
onProgress: httpPoller.onProgress,
poll: httpPoller.poll,
pollUntilDone: httpPoller.pollUntilDone,
serialize: httpPoller.serialize,
submitted: httpPoller.submitted,
};
return simplePoller;
}

/**
* Converts a Rest Client response to a response that the LRO implementation understands
* @param response - a rest client http response
* @returns - An LRO response that the LRO implementation understands
*/
function getLroResponse<TResult extends HttpResponse>(response: TResult): LroResponse<TResult> {
function getLroResponse<TResult extends HttpResponse>(
response: TResult,
): OperationResponse<TResult> {
if (Number.isNaN(response.status)) {
throw new TypeError(`Status code of the response is not a number. Value: ${response.status}`);
}
Expand Down

0 comments on commit 7ac973d

Please sign in to comment.