Skip to content

Commit

Permalink
Sync core-lro v3-beta to main branch (#29311)
Browse files Browse the repository at this point in the history
Sync core-lro v3-beta to main branch:
- api view: [diff compared with
v3](https://apiview.dev/Assemblies/Review/2c2e6c39be9f4efcb7dcb5812ec03caa?revisionId=024991bbcc9e4f10ac52b484d6ff3267&diffRevisionId=c2c407f93624426090afa05dfb58d7c1#@azure/core-lro!CreateHttpPollerOptions:interface)
- migration guide:
[here](https://github.com/Azure/azure-sdk-for-js/pull/29311/files?short_path=149185f#diff-149185f78f3ba6e8a607806071880f4954bae228de2fd7a63965abbc85c869ce)
- design doc: [loop
1](https://microsoft.sharepoint.com/:fl:/s/61554b56-c90b-4961-ba7c-61caae235335/ERp0F2QPyX9ElPkeL2U5pioB7_ar6uwHWYiTa7roChsHVw?e=FcS0YL&nav=cz0lMkZzaXRlcyUyRjYxNTU0YjU2LWM5MGItNDk2MS1iYTdjLTYxY2FhZTIzNTMzNSZkPWIhWkhjMnhhbl9nVXVNc3RET0NHaTNKMjZEQ09nVk5FRkxtTDg4UUNsZUpwaklYajhzTWlFSFRZVC02bTRGV2JkNSZmPTAxREdGMk9FWTJPUUxXSUQ2SlA1Q0pKNkk2RjVTVFRKUksmYz0lMkYmZmx1aWQ9MSZhPUxvb3BBcHAmcD0lNDBmbHVpZHglMkZsb29wLXBhZ2UtY29udGFpbmVyJng9JTdCJTIydyUyMiUzQSUyMlQwUlRVSHh0YVdOeWIzTnZablF1YzJoaGNtVndiMmx1ZEM1amIyMThZaUZhU0dNeWVHRnVYMmRWZFUxemRFUlBRMGRwTTBveU5rUkRUMmRXVGtWR1RHMU1PRGhSUTJ4bFNuQnFTVmhxT0hOTmFVVklWRmxVTFRadE5FWlhZbVExZkRBeFJFZEdNazlGTkZSRlRWRTBOMUpHUVRkYVJUSlBSazVEUkRSV1dEWTBNa1UlM0QlMjIlMkMlMjJpJTIyJTNBJTIyYjA3OTYyZWQtMWM4Ni00Zjg3LWE3OTctYjE0MDg1ZmEwYzY4JTIyJTdE),
[loop
2](https://microsoft.sharepoint.com/:fl:/s/61554b56-c90b-4961-ba7c-61caae235335/EdO7c7zhNQ5PouqkX5YbPZ4BXAnvlDCvW9SiARuN8gMcww?e=LufGPM&nav=cz0lMkZzaXRlcyUyRjYxNTU0YjU2LWM5MGItNDk2MS1iYTdjLTYxY2FhZTIzNTMzNSZkPWIhWkhjMnhhbl9nVXVNc3RET0NHaTNKMjZEQ09nVk5FRkxtTDg4UUNsZUpwaklYajhzTWlFSFRZVC02bTRGV2JkNSZmPTAxREdGMk9FNlRYTlozWllKVkJaSDJGMlZFTDZMQldQTTYmYz0lMkYmZmx1aWQ9MSZhPUxvb3BBcHAmcD0lNDBmbHVpZHglMkZsb29wLXBhZ2UtY29udGFpbmVyJng9JTdCJTIydyUyMiUzQSUyMlQwUlRVSHh0YVdOeWIzTnZablF1YzJoaGNtVndiMmx1ZEM1amIyMThZaUZhU0dNeWVHRnVYMmRWZFUxemRFUlBRMGRwTTBveU5rUkRUMmRXVGtWR1RHMU1PRGhSUTJ4bFNuQnFTVmhxT0hOTmFVVklWRmxVTFRadE5FWlhZbVExZkRBeFJFZEdNazlGTkZSRlRWRTBOMUpHUVRkYVJUSlBSazVEUkRSV1dEWTBNa1UlM0QlMjIlMkMlMjJpJTIyJTNBJTIyYjA3OTYyZWQtMWM4Ni00Zjg3LWE3OTctYjE0MDg1ZmEwYzVjJTIyJTdE)

Impacted SDKs:
- Currently I think no SDKs would be impacted.
    - Existing HLC SDKs would use v2, no impact;
- RLC LRO wrapped its interface with v3 and without any breakings([see
pr detail](Azure/autorest.typescript#2443)), no
impact;
- Modular would use v3. The only modular SDK that is OpenAI without LRO
operations, so no impact.

- In future there would be breaking when migrating HLC to Modular.

Main changes:
```diff
- export function createHttpPoller<TResult, TState extends OperationState<TResult>>(lro: LongRunningOperation, options?: CreateHttpPollerOptions<TResult, TState>): Promise<SimplePollerLike<TState, TResult>>;
+ export function createHttpPoller<TResult, TState extends OperationState<TResult>>(lro: RunningOperation, options?: CreateHttpPollerOptions<TResult, TState>): PollerLike<TState, TResult>;

- export interface SimplePollerLike<TState extends OperationState<TResult>, TResult> {
+ export interface PollerLike<TState extends OperationState<TResult>, TResult> extends Promise<TResult> {
-    getOperationState(): TState;
+    readonly operationState: TState | undefined;
-    getResult(): TResult | undefined;
+    readonly result: TResult | undefined;
-    isDone(): boolean;
+    readonly isDone: boolean;
-    isStopped(): boolean;
-    stopPolling(): void;
-    toString(): string;
+    serialize(): Promise<string>;
+    submitted(): Promise<void>;
    onProgress(callback: (state: TState) => void): CancelOnProgress;
    poll(options?: {
        abortSignal?: AbortSignalLike;
-     }): Promise<void>;
+     }): Promise<TState>;
    pollUntilDone(pollOptions?: {
        abortSignal?: AbortSignalLike;
    }): Promise<TResult>;   
}
```

The preview pr is merged here:
#28213.

---------

Co-authored-by: Azure SDK Bot <53356347+azure-sdk@users.noreply.github.com>
Co-authored-by: Deyaaeldeen Almahallawi <dealmaha@microsoft.com>
  • Loading branch information
3 people committed Apr 26, 2024
1 parent d67190a commit f471cf0
Show file tree
Hide file tree
Showing 23 changed files with 1,391 additions and 1,605 deletions.
675 changes: 450 additions & 225 deletions common/config/rush/pnpm-lock.yaml

Large diffs are not rendered by default.

36 changes: 31 additions & 5 deletions sdk/core/core-lro/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,47 @@
# Release History

## 2.7.3 (Unreleased)
## 3.0.0-beta.2 (2024-04-26)

### Features Added

### Breaking Changes
To migrate the existing applications to v3, please refer to [Migration Guide](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-lro/docs/MIGRATION.md).

### Bugs Fixed
Compared with v3.0.0-beta.1 there are following changes.

### Other Changes

- Remove the `isStopped` considering we deprecate `stopPolling`
- The return type for `processResult` is changed from `TResult` to `Promise<TResult>`
- Rename the property from `initialUrl` to `initialRequestUrl` for `OperationConfig`

## 2.7.2 (2024-04-09)

### Other Changes

- Revert TypeScript output target to ES2017.

## 3.0.0-beta.1 (2024-02-25)

Initial implementation of next-generation for Long Running Operations (LROs) in which we deprecate the `LroEngine` support and change the return type of `createHttpPoller` from `Promise<SimplePollerLike>` to `PollerLike`.

### Breaking Changes

- `LroEngine` is deprecated and no long supported
- The return type of `createHttpPoller` is changed from `Promise<SimplePollerLike>` to `PollerLike`
- Interfaces are renamed. `SimplePollerLike` is renamed as `PollerLike`, `LroResponse` is renamed as `OperationResponse` and `LroResourceLocationConfig` is to `ResourceLocationConfig`
- Functions `getOperationState()`, `getResult()`, `isDone()` and `isStopped()` are changed to read-only attributes `operationState`, `result`, `isDone` and `isStopped`
- Deprecate the attributes `requestMethod` and `requestPath` in `LongRunningOperation`
- `LongRunningOperation` is renamed to `RunningOperation`
- The return type for `processResult` is changed from `TResult` to `Promise<TResult>`

### Features Added

- Add a new function `serialize` to help serialize the poller
- Add a new function `submitted` to help wait for the poller submitted

### Other Changes

- Add a new parameter `TRequest` for `OperationResponse` to accept the raw request
- Export the function `deserializeState` to the public

## 2.7.1 (2024-03-20)

### Other Changes
Expand Down
94 changes: 94 additions & 0 deletions sdk/core/core-lro/docs/MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Migration Guide

This document shows the customers of v2 LRO (Long Running Operations) on how to migrate their code to use the v3 libraries.

## Main difference between v2 and v3

In v2, you have to `await` the LRO to get this poller. But `await` doesn't give you the final result, it gives you the poller to track the operation's status. This has confused some users who thought `await` would give them the final result.

To make things clearer and easier to understand, we've changed how this works in v3. Now, our poller interface blends the need to track long-running operations with the usual way of handling asynchronous programming. And this is the main difference between them.

Except that the `LroEngine` is no longer supported and you could use `createHttpPoller` to create a poller instead.

If you have an existing application that uses our v2 libaries and you're interested in updating your application to use the latest one, here are the things that you need to do for the migration:

## Creation of Poller

In v2 we have two implementations for LRO: `LroEngine` and `SimplePollerLike` with `createHttpPoller`. In v3 we deprecate the former and keep the `PollerLike` with `createHttpPoller` to build the poller. And the return type is changed from `SimplePollerLike` to `PollerLike`. The creation code would be changed as below.

From

```typescript
const pollerSetting: LongRunningOperation<TResult> = {
requestMethod: "{http-method}",
requestPath: "{path}",
sendInitialRequest: async () => {
// your code to send initial request
},
sendPollRequest: async (path) => {
// your code to trigger polling request
},
};
const httpPoller = await createHttpPoller(pollerSetting, options);
```

To

```typescript
const pollerSetting: RunningOperation<TResult> = {
sendInitialRequest: async () => {
// your code to send initial request
},
sendPollRequest: async (path) => {
// your code to trigger polling request
},
};
const httpPoller = createHttpPoller(pollerSetting, options);
```

Now please notice if you `await` the helper you would get the final result.

```typescript
const result = await httpPoller;
```

## Poller API

Also the return type for `createHttpPoller` is renamed from `SimplePollerLike` to `PollerLike`.The following table compares `SimplePollerLike` and `PollerLike`:

| operation | `SimplePollerLike` | `PollerLike` |
| -------------------------------------------------------------------------- | --------------------- | ----------------- |
| return final results | `pollUntilDone()` | `pollUntilDone()` |
| poll | `poll()` | `poll()` |
| access the current state after receiving the response of each poll request | `onProgress()` | `onProgress()` |
| check whether the operation finished | `isDone()` | `isDone` |
| stop polling | `stopPolling()` | N/A |
| check if the polling stopped | `isStopped()` | N/A |
| get the current operation state | `getOperationState()` | `operationState` |
| access the final result | `getResult()` | `result` |
| serialize the poller state | `toString()` | `serialize()` |
| wait the poller submitted successfully | N/A | `submitted` |

Please note the operation `getOperationState(): TState` is changed to attribute `operationState: TState | undefined`, so the value could be `undefined` if the poller is not initialized yet.

```ts
const status = poller.getOperationState().status;
```

now

```ts
const status = poller?.operationState?.status;
```

If you want to serialize a poller, use the `serialize` instead.

```ts
const serializeState = poller.toString();
```

now

```ts
const serializeState = await poller.serialize();
```
2 changes: 1 addition & 1 deletion sdk/core/core-lro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"name": "@azure/core-lro",
"author": "Microsoft Corporation",
"sdk-type": "client",
"version": "3.0.0-beta.2",
"type": "module",
"version": "2.7.3",
"description": "Isomorphic client library for supporting long-running operations in node.js and browser.",
"exports": {
"./package.json": "./package.json",
Expand Down
152 changes: 38 additions & 114 deletions sdk/core/core-lro/review/core-lro.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,53 +10,35 @@ import { AbortSignalLike } from '@azure/abort-controller';
export type CancelOnProgress = () => void;

// @public
export function createHttpPoller<TResult, TState extends OperationState<TResult>>(lro: LongRunningOperation, options?: CreateHttpPollerOptions<TResult, TState>): Promise<SimplePollerLike<TState, TResult>>;
export function createHttpPoller<TResult, TState extends OperationState<TResult>>(lro: RunningOperation, options?: CreateHttpPollerOptions<TResult, TState>): PollerLike<TState, TResult>;

// @public
export interface CreateHttpPollerOptions<TResult, TState> {
intervalInMs?: number;
processResult?: (result: unknown, state: TState) => TResult;
processResult?: (result: unknown, state: TState) => Promise<TResult>;
resolveOnUnsuccessful?: boolean;
resourceLocationConfig?: LroResourceLocationConfig;
resourceLocationConfig?: ResourceLocationConfig;
restoreFrom?: string;
updateState?: (state: TState, response: LroResponse) => void;
updateState?: (state: TState, response: OperationResponse) => void;
withOperationLocation?: (operationLocation: string) => void;
}

// @public
export interface LongRunningOperation<T = unknown> {
requestMethod?: string;
requestPath?: string;
sendInitialRequest: () => Promise<LroResponse<unknown>>;
sendPollRequest: (path: string, options?: {
abortSignal?: AbortSignalLike;
}) => Promise<LroResponse<T>>;
}

// @public
export class LroEngine<TResult, TState extends PollOperationState<TResult>> extends Poller<TState, TResult> {
constructor(lro: LongRunningOperation<TResult>, options?: LroEngineOptions<TResult, TState>);
delay(): Promise<void>;
}
export function deserializeState<TResult, TState extends OperationState<TResult>>(serializedState: string): RestorableOperationState<TResult, TState>;

// @public
export interface LroEngineOptions<TResult, TState> {
intervalInMs?: number;
isDone?: (lastResponse: unknown, state: TState) => boolean;
lroResourceLocationConfig?: LroResourceLocationConfig;
processResult?: (result: unknown, state: TState) => TResult;
resolveOnUnsuccessful?: boolean;
resumeFrom?: string;
updateState?: (state: TState, lastResponse: RawResponse) => void;
export interface OperationConfig {
initialRequestUrl?: string;
metadata?: Record<string, string>;
operationLocation?: string;
requestMethod?: string;
resourceLocation?: string;
}

// @public
export type LroResourceLocationConfig = "azure-async-operation" | "location" | "original-uri";

// @public
export interface LroResponse<T = unknown> {
export interface OperationResponse<T = unknown, TRequest extends RawRequest = RawRequest> {
flatResponse: T;
rawResponse: RawResponse;
rawResponse: RawResponse<TRequest>;
}

// @public
Expand All @@ -70,110 +52,52 @@ export interface OperationState<TResult> {
export type OperationStatus = "notStarted" | "running" | "succeeded" | "canceled" | "failed";

// @public
export abstract class Poller<TState extends PollOperationState<TResult>, TResult> implements PollerLike<TState, TResult> {
constructor(operation: PollOperation<TState, TResult>);
cancelOperation(options?: {
abortSignal?: AbortSignalLike;
}): Promise<void>;
protected abstract delay(): Promise<void>;
getOperationState(): TState;
getResult(): TResult | undefined;
isDone(): boolean;
isStopped(): boolean;
export interface PollerLike<TState extends OperationState<TResult>, TResult> extends Promise<TResult> {
readonly isDone: boolean;
onProgress(callback: (state: TState) => void): CancelOnProgress;
protected operation: PollOperation<TState, TResult>;
readonly operationState: TState | undefined;
poll(options?: {
abortSignal?: AbortSignalLike;
}): Promise<void>;
}): Promise<TState>;
pollUntilDone(pollOptions?: {
abortSignal?: AbortSignalLike;
}): Promise<TResult>;
protected resolveOnUnsuccessful: boolean;
stopPolling(): void;
toString(): string;
readonly result: TResult | undefined;
serialize(): Promise<string>;
submitted(): Promise<void>;
}

// @public
export class PollerCancelledError extends Error {
constructor(message: string);
}

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

// @public
export class PollerStoppedError extends Error {
constructor(message: string);
}

// @public
export interface PollOperation<TState, TResult> {
// @deprecated
cancel(options?: {
abortSignal?: AbortSignalLike;
}): Promise<PollOperation<TState, TResult>>;
state: TState;
toString(): string;
update(options?: {
abortSignal?: AbortSignalLike;
fireProgress?: (state: TState) => void;
}): Promise<PollOperation<TState, TResult>>;
}

// @public
export interface PollOperationState<TResult> {
error?: Error;
isCancelled?: boolean;
isCompleted?: boolean;
isStarted?: boolean;
result?: TResult;
export interface RawRequest {
body?: unknown;
method: string;
url: string;
}

// @public
export type PollProgressCallback<TState> = (state: TState) => void;

// @public
export interface RawResponse {
export interface RawResponse<TRequest extends RawRequest = RawRequest> {
body?: unknown;
headers: {
[headerName: string]: string;
};
request: TRequest;
statusCode: number;
}

// @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<void>;
pollUntilDone(pollOptions?: {
export type ResourceLocationConfig = "azure-async-operation" | "location" | "original-uri";

// @public
export type RestorableOperationState<TResult, T extends OperationState<TResult>> = T & {
config: OperationConfig;
};

// @public
export interface RunningOperation<T = unknown> {
sendInitialRequest: () => Promise<OperationResponse<unknown>>;
sendPollRequest: (path: string, options?: {
abortSignal?: AbortSignalLike;
}): Promise<TResult>;
stopPolling(): void;
toString(): string;
}) => Promise<OperationResponse<T>>;
}

// (No @packageDocumentation comment for this package)
Expand Down

0 comments on commit f471cf0

Please sign in to comment.