[Durable Functions] Migrate to Durable Functions v2 (#431)

* Replace orchestrationClient binding type with durableClient

* Replace orchestrationClient with durableClient in the code

* Upgrade DurableTask to 2.0.0

* Update the note about Durable Functions v2 support
This commit is contained in:
Anatoli Beliaev 2020-03-18 19:05:29 -07:00 коммит произвёл GitHub
Родитель 40a245a322
Коммит 28a06c3920
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 80 добавлений и 81 удалений

Просмотреть файл

@ -25,7 +25,7 @@ Start with the sample durable app at `examples/durable/DurableApp`.
Note:
- Please make sure you are using Azure Functions **v3** runtime. There are no plans to support Durable PowerShell on Azure Functions **v1** or **v2**.
- There is no support for Durable Functions **2.x** at this point, only Durable Functions **1.x** are supported (see [Durable Functions versions overview](https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-versions)).
- Only Durable Functions **2.x** are supported (see [Durable Functions versions overview](https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-versions)). There is no plan to keep Durable Functions **1.x** support.
- Please make sure you are using the sample code version corresponding to the version of the PowerShell Worker. The programming model is still changing, so older or newer samples may not work. So, if you are trying Durable PowerShell on Azure, use the samples tagged with the version of the PowerShell worker deployed to Azure. Alternatively, take the latest PowerShell Worker code from the **dev** branch, and rebuild and run the PowerShell Worker locally.
- Only a limited number of patterns is enabled at this point:
- [Function chaining](https://docs.microsoft.com/azure/azure-functions/durable/durable-functions-overview?tabs=csharp#chaining)
@ -40,10 +40,10 @@ Before deploying your app, run the following command in the app directory:
func extensions install --powershell
```
Please note that the Microsoft.Azure.WebJobs.Extensions.DurableTask package should be pinned to a 1.* version until Durable Functions 2.x support is added. For this reason, the extensions.csproj file already includes the following line:
Please note that the Microsoft.Azure.WebJobs.Extensions.DurableTask package should be pinned to version 2.0.0 until [the fix for a known issue](https://github.com/Azure/azure-functions-durable-extension/pull/1164) is released. For this reason, the extensions.csproj file already includes the following line:
``` xml
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="1.8.3" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.0.0" />
```
## 4. App settings

Просмотреть файл

@ -17,7 +17,7 @@
},
{
"name": "starter",
"type": "orchestrationClient",
"type": "durableClient",
"direction": "in"
}
]

Просмотреть файл

@ -17,7 +17,7 @@
},
{
"name": "starter",
"type": "orchestrationClient",
"type": "durableClient",
"direction": "in"
}
]

Просмотреть файл

@ -5,6 +5,6 @@
<DefaultItemExcludes>**</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="1.8.3" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.0.0" />
</ItemGroup>
</Project>

Просмотреть файл

@ -17,7 +17,7 @@
},
{
"name": "starter",
"type": "orchestrationClient",
"type": "durableClient",
"direction": "in"
}
]

Просмотреть файл

@ -5,7 +5,6 @@
<DefaultItemExcludes>**</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="1.8.3" />
<PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.0.0" />
</ItemGroup>
</Project>

Просмотреть файл

@ -9,13 +9,13 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Durable
internal static class DurableBindings
{
private const string OrchestrationClient = "orchestrationClient";
private const string DurableClient = "durableClient";
private const string OrchestrationTrigger = "orchestrationTrigger";
private const string ActivityTrigger = "activityTrigger";
public static bool IsOrchestrationClient(string bindingType)
public static bool IsDurableClient(string bindingType)
{
return string.Compare(bindingType, OrchestrationClient, StringComparison.OrdinalIgnoreCase) == 0;
return string.Compare(bindingType, DurableClient, StringComparison.OrdinalIgnoreCase) == 0;
}
public static bool IsOrchestrationTrigger(string bindingType)
@ -31,7 +31,7 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Durable
public static bool CanParameterDeclarationBeOmitted(string bindingType)
{
// Declaring a function parameter for the orchestration client binding is allowed but not mandatory
return IsOrchestrationClient(bindingType);
return IsDurableClient(bindingType);
}
}
}

Просмотреть файл

@ -53,17 +53,17 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Durable
public void BeforeFunctionInvocation(IList<ParameterBinding> inputData)
{
// If the function is an orchestration client, then we set the OrchestrationClient
// If the function is an orchestration client, then we set the DurableClient
// in the module context for the 'Start-NewOrchestration' function to use.
if (_durableFunctionInfo.IsOrchestrationClient)
if (_durableFunctionInfo.IsDurableClient)
{
ThrowIfDurableNotEnabled();
var orchestrationClient =
inputData.First(item => item.Name == _durableFunctionInfo.OrchestrationClientBindingName)
var durableClient =
inputData.First(item => item.Name == _durableFunctionInfo.DurableClientBindingName)
.Data.ToObject();
_powerShellServices.SetOrchestrationClient(orchestrationClient);
_powerShellServices.SetDurableClient(durableClient);
}
else if (_durableFunctionInfo.IsOrchestrationFunction)
{

Просмотреть файл

@ -7,17 +7,17 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Durable
{
internal class DurableFunctionInfo
{
public DurableFunctionInfo(DurableFunctionType type, string orchestrationClientBindingName)
public DurableFunctionInfo(DurableFunctionType type, string durableClientBindingName)
{
Type = type;
OrchestrationClientBindingName = orchestrationClientBindingName;
DurableClientBindingName = durableClientBindingName;
}
public bool IsOrchestrationClient => OrchestrationClientBindingName != null;
public bool IsDurableClient => DurableClientBindingName != null;
public bool IsOrchestrationFunction => Type == DurableFunctionType.OrchestrationFunction;
public string OrchestrationClientBindingName { get; }
public string DurableClientBindingName { get; }
public DurableFunctionType Type { get; }

Просмотреть файл

@ -18,7 +18,7 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Durable
bindings.FirstOrDefault(
binding => !string.IsNullOrEmpty(binding.Key)
&& binding.Value.Direction == BindingInfo.Types.Direction.In
&& DurableBindings.IsOrchestrationClient(binding.Value.Type));
&& DurableBindings.IsDurableClient(binding.Value.Type));
var durableFunctionType = GetDurableFunctionType(bindings);

Просмотреть файл

@ -10,7 +10,7 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Durable
internal interface IPowerShellServices
{
void SetOrchestrationClient(object orchestrationClient);
void SetDurableClient(object durableClient);
void SetOrchestrationContext(OrchestrationContext orchestrationContext);

Просмотреть файл

@ -22,10 +22,10 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Durable
_pwsh = pwsh;
}
public void SetOrchestrationClient(object orchestrationClient)
public void SetDurableClient(object durableClient)
{
_pwsh.AddCommand(SetFunctionInvocationContextCommand)
.AddParameter("OrchestrationClient", orchestrationClient)
.AddParameter("DurableClient", durableClient)
.InvokeAndClearCommands();
_hasSetOrchestrationContext = true;

Просмотреть файл

@ -17,7 +17,7 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Durable
public class SetFunctionInvocationContextCommand : PSCmdlet
{
internal const string ContextKey = "OrchestrationContext";
private const string OrchestrationClientKey = "OrchestrationClient";
private const string DurableClientKey = "DurableClient";
[Parameter(Mandatory = true, ParameterSetName = ContextKey)]
public OrchestrationContext OrchestrationContext { get; set; }
@ -25,8 +25,8 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Durable
/// <summary>
/// The orchestration client.
/// </summary>
[Parameter(Mandatory = true, ParameterSetName = OrchestrationClientKey)]
public object OrchestrationClient { get; set; }
[Parameter(Mandatory = true, ParameterSetName = DurableClientKey)]
public object DurableClient { get; set; }
[Parameter(Mandatory = true, ParameterSetName = "Clear")]
public SwitchParameter Clear { get; set; }
@ -40,15 +40,15 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Durable
privateData[ContextKey] = OrchestrationContext;
break;
case OrchestrationClientKey:
privateData[OrchestrationClientKey] = OrchestrationClient;
case DurableClientKey:
privateData[DurableClientKey] = DurableClient;
break;
default:
if (Clear.IsPresent)
{
privateData.Remove(ContextKey);
privateData.Remove(OrchestrationClientKey);
privateData.Remove(DurableClientKey);
}
break;
}

Просмотреть файл

@ -9,10 +9,10 @@ function CheckIfDurableFunctionsEnabled {
}
}
function GetOrchestrationClientFromModulePrivateData {
function GetDurableClientFromModulePrivateData {
$PrivateData = $PSCmdlet.MyInvocation.MyCommand.Module.PrivateData
if ($PrivateData) {
$PrivateData['OrchestrationClient']
$PrivateData['DurableClient']
}
}
@ -22,13 +22,13 @@ function GetOrchestrationClientFromModulePrivateData {
.DESCRIPTION
Start an orchestration Azure Function with the given function name and input value.
.EXAMPLE
PS > Start-NewOrchestration -OrchestrationClient Starter -FunctionName OrchestratorFunction -InputObject "input value for the orchestration function"
PS > Start-NewOrchestration -DurableClient Starter -FunctionName OrchestratorFunction -InputObject "input value for the orchestration function"
Return the instance id of the new orchestration.
.PARAMETER FunctionName
The name of the orchestration Azure Function you want to start.
.PARAMETER InputObject
The input value that will be passed to the orchestration Azure Function.
.PARAMETER OrchestrationClient
.PARAMETER DurableClient
The orchestration client object.
#>
function Start-NewOrchestration {
@ -48,21 +48,21 @@ function Start-NewOrchestration {
[Parameter(
ValueFromPipelineByPropertyName=$true)]
[object] $OrchestrationClient
[object] $DurableClient
)
CheckIfDurableFunctionsEnabled
if ($null -eq $OrchestrationClient) {
$OrchestrationClient = GetOrchestrationClientFromModulePrivateData
if ($null -eq $OrchestrationClient) {
throw "Cannot start an orchestration function. No binding of the type 'orchestrationClient' was defined."
if ($null -eq $DurableClient) {
$DurableClient = GetDurableClientFromModulePrivateData
if ($null -eq $DurableClient) {
throw "Cannot start an orchestration function. No binding of the type 'durableClient' was defined."
}
}
$InstanceId = (New-Guid).Guid
$UriTemplate = $OrchestrationClient.creationUrls.createNewInstancePostUri
$UriTemplate = $DurableClient.creationUrls.createNewInstancePostUri
$Uri = $UriTemplate.Replace('{functionName}', $FunctionName).Replace('[/{instanceId}]', "/$InstanceId")
$Body = $InputObject | ConvertTo-Json -Compress
@ -98,15 +98,15 @@ function New-OrchestrationCheckStatusResponse {
[Parameter(
ValueFromPipelineByPropertyName=$true)]
[object] $OrchestrationClient
[object] $DurableClient
)
CheckIfDurableFunctionsEnabled
if ($null -eq $OrchestrationClient) {
$OrchestrationClient = GetOrchestrationClientFromModulePrivateData
if ($null -eq $OrchestrationClient) {
throw "Cannot create orchestration check status response. No binding of the type 'orchestrationClient' was defined."
if ($null -eq $DurableClient) {
$DurableClient = GetDurableClientFromModulePrivateData
if ($null -eq $DurableClient) {
throw "Cannot create orchestration check status response. No binding of the type 'durableClient' was defined."
}
}
@ -115,7 +115,7 @@ function New-OrchestrationCheckStatusResponse {
$requestUrlOrigin = GetUrlOrigin $requestUrl
$httpManagementPayload = @{ }
foreach ($entry in $OrchestrationClient.managementUrls.GetEnumerator()) {
foreach ($entry in $DurableClient.managementUrls.GetEnumerator()) {
$value = $entry.Value
if ($requestHasValidUrl -and (IsValidUrl $value)) {
@ -123,7 +123,7 @@ function New-OrchestrationCheckStatusResponse {
$value = $value.Replace($dataOrigin, $requestUrlOrigin)
}
$value = $value.Replace($OrchestrationClient.managementUrls.id, $InstanceId)
$value = $value.Replace($DurableClient.managementUrls.id, $InstanceId)
$httpManagementPayload.Add($entry.Name, $value)
}

Просмотреть файл

@ -17,7 +17,7 @@
},
{
"name": "starter",
"type": "orchestrationClient",
"type": "durableClient",
"direction": "in"
}
]

Просмотреть файл

@ -5,6 +5,6 @@
<DefaultItemExcludes>**</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="1.8.2" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.0.0" />
</ItemGroup>
</Project>

Просмотреть файл

@ -24,25 +24,25 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Test.Durable
private readonly Mock<IOrchestrationInvoker> _mockOrchestrationInvoker = new Mock<IOrchestrationInvoker>(MockBehavior.Strict);
[Fact]
public void BeforeFunctionInvocation_SetsOrchestrationClient_ForOrchestrationClientFunction()
public void BeforeFunctionInvocation_SetsDurableClient_ForDurableClientFunction()
{
var durableController = CreateDurableController(DurableFunctionType.None, "OrchestrationClientBindingName");
var durableController = CreateDurableController(DurableFunctionType.None, "DurableClientBindingName");
var orchestrationClient = new { FakeClientProperty = "FakeClientPropertyValue" };
var durableClient = new { FakeClientProperty = "FakeClientPropertyValue" };
var inputData = new[]
{
CreateParameterBinding("AnotherParameter", "IgnoredValue"),
CreateParameterBinding("OrchestrationClientBindingName", orchestrationClient),
CreateParameterBinding("DurableClientBindingName", durableClient),
CreateParameterBinding("YetAnotherParameter", "IgnoredValue")
};
_mockPowerShellServices.Setup(_ => _.SetOrchestrationClient(It.IsAny<object>()));
_mockPowerShellServices.Setup(_ => _.SetDurableClient(It.IsAny<object>()));
durableController.BeforeFunctionInvocation(inputData);
_mockPowerShellServices.Verify(
_ => _.SetOrchestrationClient(
It.Is<object>(c => (string)((Hashtable)c)["FakeClientProperty"] == orchestrationClient.FakeClientProperty)),
_ => _.SetDurableClient(
It.Is<object>(c => (string)((Hashtable)c)["FakeClientProperty"] == durableClient.FakeClientProperty)),
Times.Once);
}
@ -233,9 +233,9 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Test.Durable
private DurableController CreateDurableController(
DurableFunctionType durableFunctionType,
string orchestrationClientBindingName = null)
string durableClientBindingName = null)
{
var durableFunctionInfo = new DurableFunctionInfo(durableFunctionType, orchestrationClientBindingName);
var durableFunctionInfo = new DurableFunctionInfo(durableFunctionType, durableClientBindingName);
return new DurableController(
durableEnabled: true,

Просмотреть файл

@ -15,24 +15,24 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Test.Durable
public class DurableFunctionInfoFactoryTests
{
[Fact]
public void ContainsOrchestrationClientName()
public void ContainsDurableClientName()
{
var bindings = new MapField<string, BindingInfo>
{
{
"TestBindingName",
new BindingInfo { Direction = BindingInfo.Types.Direction.In, Type = "orchestrationClient" }
new BindingInfo { Direction = BindingInfo.Types.Direction.In, Type = "durableClient" }
}
};
var durableFunctionInfo = DurableFunctionInfoFactory.Create(bindings);
Assert.True(durableFunctionInfo.IsOrchestrationClient);
Assert.Equal("TestBindingName", durableFunctionInfo.OrchestrationClientBindingName);
Assert.True(durableFunctionInfo.IsDurableClient);
Assert.Equal("TestBindingName", durableFunctionInfo.DurableClientBindingName);
}
[Fact]
public void ContainsFirstInputOrchestrationClientName()
public void ContainsFirstInputDurableClientName()
{
var bindings = new MapField<string, BindingInfo>
{
@ -42,15 +42,15 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Test.Durable
},
{
"Binding2",
new BindingInfo { Direction = BindingInfo.Types.Direction.Out, Type = "orchestrationClient" }
new BindingInfo { Direction = BindingInfo.Types.Direction.Out, Type = "durableClient" }
},
{
"Binding3",
new BindingInfo { Direction = BindingInfo.Types.Direction.Inout, Type = "orchestrationClient" }
new BindingInfo { Direction = BindingInfo.Types.Direction.Inout, Type = "durableClient" }
},
{
"Binding4",
new BindingInfo { Direction = BindingInfo.Types.Direction.In, Type = "orchestrationClient" }
new BindingInfo { Direction = BindingInfo.Types.Direction.In, Type = "durableClient" }
},
{
"Binding5",
@ -60,43 +60,43 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Test.Durable
var durableFunctionInfo = DurableFunctionInfoFactory.Create(bindings);
Assert.True(durableFunctionInfo.IsOrchestrationClient);
Assert.Equal("Binding4", durableFunctionInfo.OrchestrationClientBindingName);
Assert.True(durableFunctionInfo.IsDurableClient);
Assert.Equal("Binding4", durableFunctionInfo.DurableClientBindingName);
}
[Fact]
public void ContainsNoOrchestrationClientNameIfNoBindings()
public void ContainsNoDurableClientNameIfNoBindings()
{
var durableFunctionInfo = DurableFunctionInfoFactory.Create(new MapField<string, BindingInfo>());
Assert.False(durableFunctionInfo.IsOrchestrationClient);
Assert.Null(durableFunctionInfo.OrchestrationClientBindingName);
Assert.False(durableFunctionInfo.IsDurableClient);
Assert.Null(durableFunctionInfo.DurableClientBindingName);
}
[Fact]
public void ContainsNoOrchestrationClientNameIfNoInputOrchestrationClientBindings()
public void ContainsNoDurableClientNameIfNoInputDurableClientBindings()
{
var durableFunctionInfo = DurableFunctionInfoFactory.Create(new MapField<string, BindingInfo>());
Assert.False(durableFunctionInfo.IsOrchestrationClient);
Assert.Null(durableFunctionInfo.OrchestrationClientBindingName);
Assert.False(durableFunctionInfo.IsDurableClient);
Assert.Null(durableFunctionInfo.DurableClientBindingName);
}
[Fact]
public void ContainsNoOrchestrationClientNameIfBindingNameIsEmpty()
public void ContainsNoDurableClientNameIfBindingNameIsEmpty()
{
var bindings = new MapField<string, BindingInfo>
{
{
string.Empty,
new BindingInfo { Direction = BindingInfo.Types.Direction.In, Type = "orchestrationClient" }
new BindingInfo { Direction = BindingInfo.Types.Direction.In, Type = "durableClient" }
}
};
var durableFunctionInfo = DurableFunctionInfoFactory.Create(bindings);
Assert.False(durableFunctionInfo.IsOrchestrationClient);
Assert.Null(durableFunctionInfo.OrchestrationClientBindingName);
Assert.False(durableFunctionInfo.IsDurableClient);
Assert.Null(durableFunctionInfo.DurableClientBindingName);
}
[Fact]
@ -138,7 +138,7 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Test.Durable
{
{
"Binding1",
new BindingInfo { Direction = BindingInfo.Types.Direction.In, Type = "orchestrationClient" }
new BindingInfo { Direction = BindingInfo.Types.Direction.In, Type = "durableClient" }
},
{
// orchestrationTrigger, but not Direction.In