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

Update NextLinkOperationImplementation to support LRO rehydration #2843

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5775771
implement operation id
fengzhou-msft Oct 27, 2022
218c786
calculate operation id
fengzhou-msft Nov 7, 2022
a1ef6ce
add GetOperationId method
fengzhou-msft Nov 14, 2022
2c74c21
update shared source
fengzhou-msft Nov 16, 2022
8604360
implement LRO id
fengzhou-msft Nov 16, 2022
7b52195
temporary update on DownloadSharedSource.ps1
fengzhou-msft Nov 16, 2022
3518408
Merge branch 'feature/v3' of github.com:Azure/autorest.csharp into su…
fengzhou-msft Nov 16, 2022
fc1f157
fix comment in ps
fengzhou-msft Nov 16, 2022
d67dc92
update shared files
fengzhou-msft Nov 18, 2022
a80f359
update LRO creation
fengzhou-msft Nov 18, 2022
5881c40
update shared files
fengzhou-msft Nov 18, 2022
e77551a
Merge branch 'feature/v3' of github.com:Azure/autorest.csharp into su…
fengzhou-msft Nov 18, 2022
09f8b95
Merge branch 'feature/v3' of github.com:Azure/autorest.csharp into su…
fengzhou-msft Nov 29, 2022
1a892e0
Merge branch 'feature/v3' of github.com:Azure/autorest.csharp into su…
fengzhou-msft Dec 13, 2022
cd9e928
changes for .NET 7
fengzhou-msft Dec 14, 2022
38f069e
Merge branch 'feature/v3' of github.com:Azure/autorest.csharp into su…
fengzhou-msft Dec 14, 2022
5ac5c30
update shared code
fengzhou-msft Dec 15, 2022
56d0460
revert IOperationSource change
fengzhou-msft Dec 15, 2022
96d330e
Merge branch 'feature/v3' of github.com:Azure/autorest.csharp into su…
fengzhou-msft Jan 9, 2023
176a1f3
revert samples and tests
fengzhou-msft Jan 9, 2023
92d5e20
update shared code
fengzhou-msft Jan 12, 2023
f343c36
Merge branch 'feature/v3' of github.com:Azure/autorest.csharp into su…
fengzhou-msft Jan 12, 2023
b30f757
remove FinalResponse from id
fengzhou-msft Feb 10, 2023
6fd0f01
merge feature/v3
fengzhou-msft Feb 10, 2023
ed449de
update DownloadSharedSource
fengzhou-msft Mar 1, 2023
a238aa5
Merge branch 'feature/v3' of github.com:Azure/autorest.csharp into su…
fengzhou-msft Mar 1, 2023
325718a
update shared source
fengzhou-msft Mar 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion eng/DownloadSharedSource.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ $files = @('AsyncLockWithValue.cs', 'ClientDiagnostics.cs', 'DiagnosticScope.cs'
'Multipart/MultipartContent.cs', 'AzureKeyCredentialPolicy.cs', 'AppContextSwitchHelper.cs',
'ConstantDelayStrategy.cs', 'DelayStrategy.cs', 'ExponentialDelayStrategy.cs', 'OperationPoller.cs', 'RetryAfterDelayStrategy.cs',
'ForwardsClientCallsAttribute.cs', 'AsyncLockWithValue.cs', 'VoidValue.cs')
$baseUrl = 'https://raw.githubusercontent.com/Azure/azure-sdk-for-net/main/sdk/core/Azure.Core/src/Shared/'
# TODO: temporary change to target at support_lro_rehydration branch
$baseUrl = 'https://raw.githubusercontent.com/Azure/azure-sdk-for-net/support_lro_rehydration/sdk/core/Azure.Core/src/Shared/'
Comment on lines +22 to +23
Copy link
Member Author

Choose a reason for hiding this comment

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

Revert before merge.

DownloadAll $files $baseUrl $downloadPath

#Download management Shared
Expand Down
17 changes: 16 additions & 1 deletion src/assets/Azure.Core.Shared/OperationInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ internal class OperationInternal : OperationInternalBase
public OperationInternal(
ClientDiagnostics clientDiagnostics,
IOperation operation,
Response rawResponse,
Response? rawResponse,
string? operationTypeName = null,
IEnumerable<KeyValuePair<string, string>>? scopeAttributes = null,
DelayStrategy? fallbackStrategy = null)
Expand All @@ -110,6 +110,11 @@ private OperationInternal(OperationState finalState)
protected override async ValueTask<Response> UpdateStatusAsync(bool async, CancellationToken cancellationToken) =>
async ? await _internalOperation.UpdateStatusAsync(cancellationToken).ConfigureAwait(false) : _internalOperation.UpdateStatus(cancellationToken);

public virtual string GetOperationId()
{
return _internalOperation.GetOperationId();
}

// Wrapper type that converts OperationState to OperationState<T> and can be passed to `OperationInternal<T>` constructor.
private class OperationToOperationOfTProxy : IOperation<VoidValue>
{
Expand All @@ -135,6 +140,11 @@ public async ValueTask<OperationState<VoidValue>> UpdateStateAsync(bool async, C

return OperationState<VoidValue>.Failure(state.RawResponse, state.OperationFailedException);
}

public string GetOperationId()
{
return _operation.GetOperationId();
}
}
}

Expand Down Expand Up @@ -173,6 +183,11 @@ internal interface IOperation
/// </list>
/// </returns>
ValueTask<OperationState> UpdateStateAsync(bool async, CancellationToken cancellationToken);

/// <summary>
/// To get the Id of the operation for rehydration purpose.
/// </summary>
string GetOperationId();
}

/// <summary>
Expand Down
19 changes: 16 additions & 3 deletions src/assets/Azure.Core.Shared/OperationInternalOfT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core.Pipeline;
Expand Down Expand Up @@ -53,7 +54,7 @@ internal class OperationInternal<T> : OperationInternalBase
{
private readonly IOperation<T> _operation;
private readonly AsyncLockWithValue<OperationState<T>> _stateLock;
private Response _rawResponse;
private Response? _rawResponse;

/// <summary>
/// Initializes a new instance of the <see cref="OperationInternal"/> class in a final successful state.
Expand Down Expand Up @@ -95,7 +96,7 @@ internal class OperationInternal<T> : OperationInternalBase
public OperationInternal(
ClientDiagnostics clientDiagnostics,
IOperation<T> operation,
Response rawResponse,
Response? rawResponse,
string? operationTypeName = null,
IEnumerable<KeyValuePair<string, string>>? scopeAttributes = null,
DelayStrategy? fallbackStrategy = null)
Expand All @@ -116,7 +117,7 @@ private OperationInternal(OperationState<T> finalState)
_stateLock = new AsyncLockWithValue<OperationState<T>>(finalState);
}

public override Response RawResponse => _stateLock.TryGetValue(out var state) ? state.RawResponse : _rawResponse;
public override Response RawResponse => (_stateLock.TryGetValue(out var state) ? state.RawResponse : _rawResponse) ?? throw new InvalidOperationException("The operation does not have a response yet. Please call UpdateStatus or WaitForCompletion first.");

public override bool HasCompleted => _stateLock.HasValue;

Expand Down Expand Up @@ -279,6 +280,11 @@ protected override async ValueTask<Response> UpdateStatusAsync(bool async, Cance
}
}

public virtual string GetOperationId()
{
return _operation.GetOperationId();
}

private static Response GetResponseFromState(OperationState<T> state)
{
if (state.HasSucceeded)
Expand All @@ -293,6 +299,8 @@ private class FinalOperation : IOperation<T>
{
public ValueTask<OperationState<T>> UpdateStateAsync(bool async, CancellationToken cancellationToken)
=> throw new NotSupportedException("The operation has already completed");

public string GetOperationId() => string.Empty;
}
}

Expand Down Expand Up @@ -333,6 +341,11 @@ internal interface IOperation<T>
/// </list>
/// </returns>
ValueTask<OperationState<T>> UpdateStateAsync(bool async, CancellationToken cancellationToken);

/// <summary>
/// To get the Id of the operation for rehydration purpose.
/// </summary>
string GetOperationId();
}

/// <summary>
Expand Down
62 changes: 61 additions & 1 deletion src/assets/Generator.Shared/NextLinkOperationImplementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
#nullable enable

using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core.Pipeline;
Expand Down Expand Up @@ -62,6 +64,38 @@ public static IOperation<T> Create<T>(
return new OperationToOperationOfT<T>(operationSource, operation);
}

public static IOperation? Create(
HttpPipeline pipeline,
string id,
string? apiVersionOverride = null)
{
var lroDetails = BinaryData.FromBytes(Convert.FromBase64String(id)).ToObjectFromJson<Dictionary<string, string>>();
Copy link
Member Author

@fengzhou-msft fengzhou-msft Mar 1, 2023

Choose a reason for hiding this comment

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

Is there a more efficient way to encode and decode the id?

if (!Uri.TryCreate(lroDetails["InitialUri"], UriKind.Absolute, out var startRequestUri))
throw new InvalidOperationException("Invalid initial URI");
if (!lroDetails.TryGetValue("NextRequestUri", out var nextRequestUri))
throw new InvalidOperationException("Invalid next request URI");
RequestMethod requestMethod = new RequestMethod(lroDetails["RequestMethod"]);
bool originalResponseHasLocation = bool.Parse(lroDetails["OriginalResponseHasLocation"]);
string lastKnownLocation = lroDetails["LastKnownLocation"];
if (!Enum.TryParse(lroDetails["FinalStateVia"], out OperationFinalStateVia finalStateVia))
finalStateVia = OperationFinalStateVia.Location;
string? apiVersionStr = apiVersionOverride ?? (TryGetApiVersion(startRequestUri, out ReadOnlySpan<char> apiVersion) ? apiVersion.ToString() : null);
if (!Enum.TryParse(lroDetails["HeaderSource"], out HeaderSource headerSource))
headerSource = HeaderSource.None;

return new NextLinkOperationImplementation(pipeline, requestMethod, startRequestUri, nextRequestUri, headerSource, originalResponseHasLocation, lastKnownLocation, finalStateVia, apiVersionStr);
}

public static IOperation<T>? Create<T>(
IOperationSource<T> operationSource,
HttpPipeline pipeline,
string id,
string? apiVersionOverride = null)
{
var operation = Create(pipeline, id, apiVersionOverride);
return new OperationToOperationOfT<T>(operationSource, operation!);
}

private NextLinkOperationImplementation(
HttpPipeline pipeline,
RequestMethod requestMethod,
Expand All @@ -84,6 +118,22 @@ private NextLinkOperationImplementation(
_apiVersion = apiVersion;
}

public string GetOperationId()
{
var lroDetails = new Dictionary<string, string?>()
{
["HeaderSource"] = _headerSource.ToString(),
["NextRequestUri"] = _nextRequestUri,
["InitialUri"] = _startRequestUri.AbsoluteUri,
["RequestMethod"] = _requestMethod.ToString(),
["OriginalResponseHasLocation"] = _originalResponseHasLocation.ToString(),
["LastKnownLocation"] = _lastKnownLocation,
["FinalStateVia"] = _finalStateVia.ToString()
};
var lroData = BinaryData.FromObjectAsJson(lroDetails);
return Convert.ToBase64String(lroData.ToArray());
}

public async ValueTask<OperationState> UpdateStateAsync(bool async, CancellationToken cancellationToken)
{
Response response = await GetResponseAsync(async, _nextRequestUri, cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -402,6 +452,11 @@ public CompletedOperation(OperationState operationState)
}

public ValueTask<OperationState> UpdateStateAsync(bool async, CancellationToken cancellationToken) => new(_operationState);

public string GetOperationId()
{
return string.Empty;
}
}

private sealed class OperationToOperationOfT<T> : IOperation<T>
Expand Down Expand Up @@ -434,6 +489,11 @@ public async ValueTask<OperationState<T>> UpdateStateAsync(bool async, Cancellat

return OperationState<T>.Pending(state.RawResponse);
}

public string GetOperationId()
{
return _operation.GetOperationId();
}
}
}
}
11 changes: 6 additions & 5 deletions src/assets/Generator.Shared/ProtocolOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,8 @@ internal ProtocolOperation(ClientDiagnostics clientDiagnostics, HttpPipeline pip
_operation = new OperationInternal<T>(clientDiagnostics, this, response, scopeName);
}

#pragma warning disable CA1822
// This scenario is currently unsupported.
// See: https://github.com/Azure/autorest.csharp/issues/2158.
/// <inheritdoc />
public override string Id => throw new NotSupportedException();
#pragma warning restore CA1822
public override string Id => _nextLinkOperation.GetOperationId();

/// <inheritdoc />
public override T Value => _operation.Value;
Expand Down Expand Up @@ -69,5 +65,10 @@ async ValueTask<OperationState<T>> IOperation<T>.UpdateStateAsync(bool async, Ca

return OperationState<T>.Pending(state.RawResponse);
}

public string GetOperationId()
{
return _nextLinkOperation.GetOperationId();
}
}
}