diff --git a/docs/designs/PowerShell-AzF-Overall-Design.md b/docs/designs/PowerShell-AzF-Overall-Design.md index f0db2442..73905c1d 100644 --- a/docs/designs/PowerShell-AzF-Overall-Design.md +++ b/docs/designs/PowerShell-AzF-Overall-Design.md @@ -551,17 +551,17 @@ We had a prototype of Durable Functions in PowerShell worker to enable the '_Fun 2. Make the orchestrator function able to be stopped at certain point safely. 3. Make the PowerShell worker able to replay an orchestrator function, namely skipping the actions that are done in previous runs/replays based on the save logs. -They were solved by introducing the new cmdlet "_Invoke-ActivityFunction_" plus having the worker invoke the orchestrator function with the async PowerShell API. +They were solved by introducing the new cmdlet "_Invoke-DurableActivity_" plus having the worker invoke the orchestrator function with the async PowerShell API. Internally, the worker shares context information with the cmdlet, including _the existing saved logs_ sent from the host about the running orchestrator function and _a wait handler_ - let's call it A - which the cmdlet will set after it triggers an activity function. The async API used to start the orchestrator function returns _another wait handler_ - let's call it B - which will be set when the invocation finishes. Then the invoking thread will call '_WaitHandler.WaitAny_' on those two wait handlers. - If the call to '_WaitAny_' returns because the wait handler A was set, then that means an activity function was just triggered, and the orchestrator function should be stopped now (it will be triggered again later after the activity function finishes). So, in this case, the invoking thread will stop the orchestrator function that is running asynchronously. - If the call to '_WaitAny_' returns because the wait handler B was set, then that means the orchestrator function has run to its completion. -The cmdlet '_Invoke-ActivityFunction_' has the following syntax, the '_-FunctionName_' being the name of the activity function to invoke and '_-Input_' being the argument to the activity function. +The cmdlet '_Invoke-DurableActivity_' has the following syntax, the '_-FunctionName_' being the name of the activity function to invoke and '_-Input_' being the argument to the activity function. ```powershell -Invoke-ActivityFunction [-FunctionName] [[-Input] ] [] +Invoke-DurableActivity [-FunctionName] [[-Input] ] [] ``` When it's invoked to trigger an activity function, it first checks the existing logs shared by the worker to see if this invocation of the activity function has already done previously. If so, the cmdlet simply returns the result. If not, the cmdlet will @@ -570,7 +570,7 @@ When it's invoked to trigger an activity function, it first checks the existing - set the wait handler shared by the worker to notify the worker that the activity function is triggered; - wait on a private wait handler that will only be set when the '_StopProcessing_' method of the cmdlet is called. That method gets called only when the pipeline where this cmdlet is running in is being stopped. -The third step is very important in this stop-and-replay model of Durable Functions, because when stopping an invocation that is running asynchronously, we don't want that to interrupt arbitrary code execution that is happening in the pipeline. By having the cmdlet '_Invoke-ActivityFunction_' wait for '_StopProcessing_' to be called, we know for sure that the pipeline execution pauses at a safe place, ready for being stopped by the invoking thread. +The third step is very important in this stop-and-replay model of Durable Functions, because when stopping an invocation that is running asynchronously, we don't want that to interrupt arbitrary code execution that is happening in the pipeline. By having the cmdlet '_Invoke-DurableActivity_' wait for '_StopProcessing_' to be called, we know for sure that the pipeline execution pauses at a safe place, ready for being stopped by the invoking thread. The following is an example of PowerShell Durable Function that runs in the Function Chaining pattern: @@ -583,9 +583,9 @@ param($context) $output = @() -$output += Invoke-ActivityFunction -FunctionName "E1_SayHello" -Input "Tokyo" -$output += Invoke-ActivityFunction -FunctionName "E1_SayHello" -Input "Seattle" -$output += Invoke-ActivityFunction -FunctionName "E1_SayHello" -Input "London" +$output += Invoke-DurableActivity -FunctionName "E1_SayHello" -Input "Tokyo" +$output += Invoke-DurableActivity -FunctionName "E1_SayHello" -Input "Seattle" +$output += Invoke-DurableActivity -FunctionName "E1_SayHello" -Input "London" return $output ``` diff --git a/examples/durable/DurableApp/CustomStatusOrchestrator/run.ps1 b/examples/durable/DurableApp/CustomStatusOrchestrator/run.ps1 index 7fdd3843..a0201f1b 100644 --- a/examples/durable/DurableApp/CustomStatusOrchestrator/run.ps1 +++ b/examples/durable/DurableApp/CustomStatusOrchestrator/run.ps1 @@ -7,13 +7,13 @@ Write-Host 'CustomStatusOrchestrator: started.' $output = @() Set-DurableCustomStatus -CustomStatus 'Processing Tokyo' -$output += Invoke-ActivityFunction -FunctionName 'SayHello' -Input 'Tokyo' +$output += Invoke-DurableActivity -FunctionName 'SayHello' -Input 'Tokyo' Set-DurableCustomStatus -CustomStatus @{ ProgressMessage = 'Processing Seattle'; Stage = 2 } -$output += Invoke-ActivityFunction -FunctionName 'SayHello' -Input 'Seattle' +$output += Invoke-DurableActivity -FunctionName 'SayHello' -Input 'Seattle' Set-DurableCustomStatus -CustomStatus @('Processing London', 'Last stage') -$output += Invoke-ActivityFunction -FunctionName 'SayHello' -Input 'London' +$output += Invoke-DurableActivity -FunctionName 'SayHello' -Input 'London' Set-DurableCustomStatus 'Processing completed' diff --git a/examples/durable/DurableApp/FanOutFanInOrchestrator/run.ps1 b/examples/durable/DurableApp/FanOutFanInOrchestrator/run.ps1 index 193de604..064903aa 100644 --- a/examples/durable/DurableApp/FanOutFanInOrchestrator/run.ps1 +++ b/examples/durable/DurableApp/FanOutFanInOrchestrator/run.ps1 @@ -6,7 +6,7 @@ Write-Host 'FanOutFanInOrchestrator: started.' $parallelTasks = foreach ($Name in 'Tokyo', 'Seattle', 'London') { - Invoke-ActivityFunction -FunctionName 'SayHello' -Input $Name -NoWait + Invoke-DurableActivity -FunctionName 'SayHello' -Input $Name -NoWait } $output = Wait-DurableTask -Task $parallelTasks diff --git a/examples/durable/DurableApp/FunctionChainingOrchestrator/run.ps1 b/examples/durable/DurableApp/FunctionChainingOrchestrator/run.ps1 index cf57c8ce..c1aa4a6c 100644 --- a/examples/durable/DurableApp/FunctionChainingOrchestrator/run.ps1 +++ b/examples/durable/DurableApp/FunctionChainingOrchestrator/run.ps1 @@ -6,9 +6,9 @@ Write-Host 'FunctionChainingOrchestrator: started.' $output = @() -$output += Invoke-ActivityFunction -FunctionName 'SayHello' -Input 'Tokyo' -$output += Invoke-ActivityFunction -FunctionName 'SayHello' -Input 'Seattle' -$output += Invoke-ActivityFunction -FunctionName 'SayHello' -Input 'London' +$output += Invoke-DurableActivity -FunctionName 'SayHello' -Input 'Tokyo' +$output += Invoke-DurableActivity -FunctionName 'SayHello' -Input 'Seattle' +$output += Invoke-DurableActivity -FunctionName 'SayHello' -Input 'London' Write-Host 'FunctionChainingOrchestrator: finished.' diff --git a/examples/durable/DurableApp/FunctionChainingWithRetriesOrchestrator/run.ps1 b/examples/durable/DurableApp/FunctionChainingWithRetriesOrchestrator/run.ps1 index ec1eef1c..3586352d 100644 --- a/examples/durable/DurableApp/FunctionChainingWithRetriesOrchestrator/run.ps1 +++ b/examples/durable/DurableApp/FunctionChainingWithRetriesOrchestrator/run.ps1 @@ -10,8 +10,8 @@ $retryOptions = New-DurableRetryOptions ` -FirstRetryInterval (New-Timespan -Seconds 1) ` -MaxNumberOfAttempts 7 -$output += Invoke-ActivityFunction -FunctionName 'FlakyActivity' -Input 'Tokyo' -RetryOptions $retryOptions -$output += Invoke-ActivityFunction -FunctionName 'FlakyActivity' -Input 'Seattle' -RetryOptions $retryOptions -$output += Invoke-ActivityFunction -FunctionName 'FlakyActivity' -Input 'London' -RetryOptions $retryOptions +$output += Invoke-DurableActivity -FunctionName 'FlakyActivity' -Input 'Tokyo' -RetryOptions $retryOptions +$output += Invoke-DurableActivity -FunctionName 'FlakyActivity' -Input 'Seattle' -RetryOptions $retryOptions +$output += Invoke-DurableActivity -FunctionName 'FlakyActivity' -Input 'London' -RetryOptions $retryOptions $output diff --git a/examples/durable/DurableApp/HttpStart/run.ps1 b/examples/durable/DurableApp/HttpStart/run.ps1 index 3388cd3e..c05ba8df 100644 --- a/examples/durable/DurableApp/HttpStart/run.ps1 +++ b/examples/durable/DurableApp/HttpStart/run.ps1 @@ -4,10 +4,10 @@ param($Request, $TriggerMetadata) Write-Host 'HttpStart started' -$InstanceId = Start-NewOrchestration -FunctionName $Request.Params.FunctionName -InputObject $Request.Query.Input +$InstanceId = Start-DurableOrchestration -FunctionName $Request.Params.FunctionName -InputObject $Request.Query.Input Write-Host "Started orchestration $($Request.Params.FunctionName) with ID = '$InstanceId'" -$Response = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId +$Response = New-DurableOrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId Push-OutputBinding -Name Response -Value $Response Write-Host 'HttpStart completed' diff --git a/examples/durable/DurableApp/HumanInteractionOrchestrator/run.ps1 b/examples/durable/DurableApp/HumanInteractionOrchestrator/run.ps1 index f9146ec5..6f07eada 100644 --- a/examples/durable/DurableApp/HumanInteractionOrchestrator/run.ps1 +++ b/examples/durable/DurableApp/HumanInteractionOrchestrator/run.ps1 @@ -10,7 +10,7 @@ $duration = New-TimeSpan -Seconds $Context.Input.Duration $managerId = $Context.Input.ManagerId $skipManagerId = $Context.Input.SkipManagerId -$output += Invoke-ActivityFunction -FunctionName "RequestApproval" -Input $managerId +$output += Invoke-DurableActivity -FunctionName "RequestApproval" -Input $managerId $durableTimeoutEvent = Start-DurableTimer -Duration $duration -NoWait $approvalEvent = Start-DurableExternalEventListener -EventName "ApprovalEvent" -NoWait @@ -19,10 +19,10 @@ $firstEvent = Wait-DurableTask -Task @($approvalEvent, $durableTimeoutEvent) -An if ($approvalEvent -eq $firstEvent) { Stop-DurableTimerTask -Task $durableTimeoutEvent - $output += Invoke-ActivityFunction -FunctionName "ProcessApproval" -Input $approvalEvent + $output += Invoke-DurableActivity -FunctionName "ProcessApproval" -Input $approvalEvent } else { - $output += Invoke-ActivityFunction -FunctionName "EscalateApproval" -Input $skipManagerId + $output += Invoke-DurableActivity -FunctionName "EscalateApproval" -Input $skipManagerId } Write-Host 'HumanInteractionOrchestrator: finished.' diff --git a/examples/durable/DurableApp/HumanInteractionStart/run.ps1 b/examples/durable/DurableApp/HumanInteractionStart/run.ps1 index 6608dcbe..18239a76 100644 --- a/examples/durable/DurableApp/HumanInteractionStart/run.ps1 +++ b/examples/durable/DurableApp/HumanInteractionStart/run.ps1 @@ -6,10 +6,10 @@ Write-Host 'HumanInteractionStart started' $OrchestratorInputs = @{ Duration = 45; ManagerId = 1; SkipManagerId = 2 } -$InstanceId = Start-NewOrchestration -FunctionName 'HumanInteractionOrchestrator' -InputObject $OrchestratorInputs +$InstanceId = Start-DurableOrchestration -FunctionName 'HumanInteractionOrchestrator' -InputObject $OrchestratorInputs Write-Host "Started orchestration with ID = '$InstanceId'" -$Response = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId +$Response = New-DurableOrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId Push-OutputBinding -Name Response -Value $Response Write-Host 'HumanInteractionStart completed' diff --git a/examples/durable/DurableApp/MonitorOrchestrator/run.ps1 b/examples/durable/DurableApp/MonitorOrchestrator/run.ps1 index 20ab3e17..0c8fc541 100644 --- a/examples/durable/DurableApp/MonitorOrchestrator/run.ps1 +++ b/examples/durable/DurableApp/MonitorOrchestrator/run.ps1 @@ -12,10 +12,10 @@ $pollingInterval = New-TimeSpan -Seconds $Context.Input.PollingInterval $expiryTime = $Context.Input.ExpiryTime while ($Context.CurrentUtcDateTime -lt $expiryTime) { - $jobStatus = Invoke-ActivityFunction -FunctionName 'GetJobStatus' -Input $jobId + $jobStatus = Invoke-DurableActivity -FunctionName 'GetJobStatus' -Input $jobId if ($jobStatus -eq "Completed") { # Perform an action when a condition is met. - $output += Invoke-ActivityFunction -FunctionName 'SendAlert' -Input $machineId + $output += Invoke-DurableActivity -FunctionName 'SendAlert' -Input $machineId break } diff --git a/examples/durable/DurableApp/MonitorStart/run.ps1 b/examples/durable/DurableApp/MonitorStart/run.ps1 index 02d2ab81..e4311449 100644 --- a/examples/durable/DurableApp/MonitorStart/run.ps1 +++ b/examples/durable/DurableApp/MonitorStart/run.ps1 @@ -6,10 +6,10 @@ Write-Host 'MonitorStart started' $OrchestratorInputs = @{ JobId = 1; MachineId = 1; PollingInterval = 10; ExpiryTime = (Get-Date).ToUniversalTime().AddSeconds(60) } -$InstanceId = Start-NewOrchestration -FunctionName 'MonitorOrchestrator' -InputObject $OrchestratorInputs +$InstanceId = Start-DurableOrchestration -FunctionName 'MonitorOrchestrator' -InputObject $OrchestratorInputs Write-Host "Started orchestration with ID = '$InstanceId'" -$Response = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId +$Response = New-DurableOrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId Push-OutputBinding -Name Response -Value $Response Write-Host 'MonitorStart completed' diff --git a/examples/durable/LongRunningHttpApp/HttpTrigger/run.ps1 b/examples/durable/LongRunningHttpApp/HttpTrigger/run.ps1 index 0aa170f7..59b9faf5 100644 --- a/examples/durable/LongRunningHttpApp/HttpTrigger/run.ps1 +++ b/examples/durable/LongRunningHttpApp/HttpTrigger/run.ps1 @@ -4,10 +4,10 @@ param($Request, $TriggerMetadata) Write-Host "HttpTrigger started" -$InstanceId = Start-NewOrchestration -FunctionName 'MyOrchestrator' -InputObject $Request.Query +$InstanceId = Start-DurableOrchestration -FunctionName 'MyOrchestrator' -InputObject $Request.Query Write-Host "Started orchestration with ID = '$InstanceId'" -$Response = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId +$Response = New-DurableOrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId Push-OutputBinding -Name Response -Value $Response Write-Host "HttpTrigger completed" diff --git a/examples/durable/LongRunningHttpApp/MyOrchestrator/run.ps1 b/examples/durable/LongRunningHttpApp/MyOrchestrator/run.ps1 index 1325f80f..c40d3ab6 100644 --- a/examples/durable/LongRunningHttpApp/MyOrchestrator/run.ps1 +++ b/examples/durable/LongRunningHttpApp/MyOrchestrator/run.ps1 @@ -2,7 +2,7 @@ param($Context) Write-Host "MyOrchestrator: started. Input: $($Context.Input)" -$activityResult = Invoke-ActivityFunction -FunctionName "LongRunningActivity" -Input $Context.Input +$activityResult = Invoke-DurableActivity -FunctionName "LongRunningActivity" -Input $Context.Input Write-Host "MyOrchestrator: Returned from LongRunningActivity: '$activityResult'" Write-Host "MyOrchestrator: finished." diff --git a/src/Durable/Commands/InvokeActivityFunctionCommand.cs b/src/Durable/Commands/InvokeDurableActivityCommand.cs similarity index 93% rename from src/Durable/Commands/InvokeActivityFunctionCommand.cs rename to src/Durable/Commands/InvokeDurableActivityCommand.cs index 7dda9e35..ba9b429f 100644 --- a/src/Durable/Commands/InvokeActivityFunctionCommand.cs +++ b/src/Durable/Commands/InvokeDurableActivityCommand.cs @@ -12,10 +12,10 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Durable.Commands using Microsoft.Azure.Functions.PowerShellWorker.Durable.Tasks; /// - /// Invoke an activity function. + /// Invoke a durable activity. /// - [Cmdlet("Invoke", "ActivityFunction")] - public class InvokeActivityFunctionCommand : PSCmdlet + [Cmdlet("Invoke", "DurableActivity")] + public class InvokeDurableActivityCommand : PSCmdlet { /// /// Gets and sets the activity function name. diff --git a/src/Durable/DurableController.cs b/src/Durable/DurableController.cs index 59015d23..6b1f31bb 100644 --- a/src/Durable/DurableController.cs +++ b/src/Durable/DurableController.cs @@ -50,7 +50,7 @@ internal DurableController( public void BeforeFunctionInvocation(IList inputData) { // If the function is an orchestration client, then we set the DurableClient - // in the module context for the 'Start-NewOrchestration' function to use. + // in the module context for the 'Start-DurableOrchestration' function to use. if (_durableFunctionInfo.IsDurableClient) { var durableClient = diff --git a/src/Modules/Microsoft.Azure.Functions.PowerShellWorker/Microsoft.Azure.Functions.PowerShellWorker.psd1 b/src/Modules/Microsoft.Azure.Functions.PowerShellWorker/Microsoft.Azure.Functions.PowerShellWorker.psd1 index ee6bcd24..3e62ea1e 100644 --- a/src/Modules/Microsoft.Azure.Functions.PowerShellWorker/Microsoft.Azure.Functions.PowerShellWorker.psd1 +++ b/src/Modules/Microsoft.Azure.Functions.PowerShellWorker/Microsoft.Azure.Functions.PowerShellWorker.psd1 @@ -50,14 +50,14 @@ NestedModules = @('Microsoft.Azure.Functions.PowerShellWorker.psm1', 'Microsoft. # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. FunctionsToExport = @( 'New-DurableRetryOptions', - 'New-OrchestrationCheckStatusResponse', + 'New-DurableOrchestrationCheckStatusResponse', 'Send-DurableExternalEvent', - 'Start-NewOrchestration') + 'Start-DurableOrchestration') # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @( 'Get-OutputBinding', - 'Invoke-ActivityFunction', + 'Invoke-DurableActivity', 'Push-OutputBinding', 'Set-DurableCustomStatus', 'Set-FunctionInvocationContext', @@ -72,6 +72,9 @@ VariablesToExport = @() # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. AliasesToExport = @( + 'Invoke-ActivityFunction', + 'New-OrchestrationCheckStatusResponse', + 'Start-NewOrchestration', 'Wait-ActivityFunction') # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. diff --git a/src/Modules/Microsoft.Azure.Functions.PowerShellWorker/Microsoft.Azure.Functions.PowerShellWorker.psm1 b/src/Modules/Microsoft.Azure.Functions.PowerShellWorker/Microsoft.Azure.Functions.PowerShellWorker.psm1 index 6c99198e..abeb7e77 100644 --- a/src/Modules/Microsoft.Azure.Functions.PowerShellWorker/Microsoft.Azure.Functions.PowerShellWorker.psm1 +++ b/src/Modules/Microsoft.Azure.Functions.PowerShellWorker/Microsoft.Azure.Functions.PowerShellWorker.psm1 @@ -5,6 +5,9 @@ # Set aliases for cmdlets to export Set-Alias -Name Wait-ActivityFunction -Value Wait-DurableTask +Set-Alias -Name Invoke-ActivityFunction -Value Invoke-DurableActivity +Set-Alias -Name New-OrchestrationCheckStatusResponse -Value New-DurableOrchestrationCheckStatusResponse +Set-Alias -Name Start-NewOrchestration -Value Start-DurableOrchestration function GetDurableClientFromModulePrivateData { $PrivateData = $PSCmdlet.MyInvocation.MyCommand.Module.PrivateData @@ -22,7 +25,7 @@ function GetDurableClientFromModulePrivateData { .DESCRIPTION Start an orchestration Azure Function with the given function name and input value. .EXAMPLE - PS > Start-NewOrchestration -DurableClient Starter -FunctionName OrchestratorFunction -InputObject "input value for the orchestration function" + PS > Start-DurableOrchestration -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. @@ -31,7 +34,7 @@ function GetDurableClientFromModulePrivateData { .PARAMETER DurableClient The orchestration client object. #> -function Start-NewOrchestration { +function Start-DurableOrchestration { [CmdletBinding()] param( [Parameter( @@ -78,7 +81,7 @@ function GetUrlOrigin([uri]$Url) { $fixedOriginUrl.ToString() } -function New-OrchestrationCheckStatusResponse { +function New-DurableOrchestrationCheckStatusResponse { [CmdletBinding()] param( [Parameter( diff --git a/test/E2E/Azure.Functions.PowerShellWorker.E2E/Azure.Functions.PowerShellWorker.E2E/DurableEndToEndTests.cs b/test/E2E/Azure.Functions.PowerShellWorker.E2E/Azure.Functions.PowerShellWorker.E2E/DurableEndToEndTests.cs index 11aeb50c..435fa86f 100644 --- a/test/E2E/Azure.Functions.PowerShellWorker.E2E/Azure.Functions.PowerShellWorker.E2E/DurableEndToEndTests.cs +++ b/test/E2E/Azure.Functions.PowerShellWorker.E2E/Azure.Functions.PowerShellWorker.E2E/DurableEndToEndTests.cs @@ -95,6 +95,58 @@ public async Task DurableClientFollowsAsyncPattern() } } + [Fact] + public async Task LegacyDurableCommandNamesStillWork() + { + var initialResponse = await Utilities.GetHttpTriggerResponse("DurableClientLegacyNames", queryString: string.Empty); + Assert.Equal(HttpStatusCode.Accepted, initialResponse.StatusCode); + + var initialResponseBody = await initialResponse.Content.ReadAsStringAsync(); + dynamic initialResponseBodyObject = JsonConvert.DeserializeObject(initialResponseBody); + var statusQueryGetUri = (string)initialResponseBodyObject.statusQueryGetUri; + + var startTime = DateTime.UtcNow; + + using (var httpClient = new HttpClient()) + { + while (true) + { + var statusResponse = await httpClient.GetAsync(statusQueryGetUri); + switch (statusResponse.StatusCode) + { + case HttpStatusCode.Accepted: + { + var statusResponseBody = await GetResponseBodyAsync(statusResponse); + var runtimeStatus = (string)statusResponseBody.runtimeStatus; + Assert.True( + runtimeStatus == "Running" || runtimeStatus == "Pending", + $"Unexpected runtime status: {runtimeStatus}"); + + if (DateTime.UtcNow > startTime + _orchestrationCompletionTimeout) + { + Assert.True(false, $"The orchestration has not completed after {_orchestrationCompletionTimeout}"); + } + + await Task.Delay(TimeSpan.FromSeconds(2)); + break; + } + + case HttpStatusCode.OK: + { + var statusResponseBody = await GetResponseBodyAsync(statusResponse); + Assert.Equal("Completed", (string)statusResponseBody.runtimeStatus); + Assert.Equal("Hello Tokyo", statusResponseBody.output[0].ToString()); + return; + } + + default: + Assert.True(false, $"Unexpected orchestration status code: {statusResponse.StatusCode}"); + break; + } + } + } + } + [Fact] public async Task ActivityExceptionIsPropagatedThroughOrchestrator() { diff --git a/test/E2E/TestFunctionApp/CurrentUtcDateTimeClient/run.ps1 b/test/E2E/TestFunctionApp/CurrentUtcDateTimeClient/run.ps1 index ac48efc0..671f110d 100644 --- a/test/E2E/TestFunctionApp/CurrentUtcDateTimeClient/run.ps1 +++ b/test/E2E/TestFunctionApp/CurrentUtcDateTimeClient/run.ps1 @@ -6,10 +6,10 @@ Write-Host "CurrentUtcDateTimeClient started" $ErrorActionPreference = 'Stop' -$InstanceId = Start-NewOrchestration -FunctionName 'CurrentUtcDateTimeOrchestrator' -InputObject 'Hello' +$InstanceId = Start-DurableOrchestration -FunctionName 'CurrentUtcDateTimeOrchestrator' -InputObject 'Hello' Write-Host "Started orchestration with ID = '$InstanceId'" -$Response = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId +$Response = New-DurableOrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId Push-OutputBinding -Name Response -Value $Response Write-Host "CurrentUtcDateTimeClient completed" diff --git a/test/E2E/TestFunctionApp/CurrentUtcDateTimeOrchestrator/run.ps1 b/test/E2E/TestFunctionApp/CurrentUtcDateTimeOrchestrator/run.ps1 index 9011b361..1c050b6d 100644 --- a/test/E2E/TestFunctionApp/CurrentUtcDateTimeOrchestrator/run.ps1 +++ b/test/E2E/TestFunctionApp/CurrentUtcDateTimeOrchestrator/run.ps1 @@ -25,7 +25,7 @@ Add-Content -Value $Context.CurrentUtcDateTime -Path $path Add-Content -Value $Context.CurrentUtcDateTime -Path $path # Checks that CurrentUtcDateTime updates following a completed activity function -$activityResults += Invoke-ActivityFunction -FunctionName "DurableActivity" -Input "Tokyo" +$activityResults += Invoke-DurableActivity -FunctionName "DurableActivity" -Input "Tokyo" # Add-Content -Value $Context.CurrentUtcDateTime -Path $path @@ -33,11 +33,11 @@ Write-Host "About to start asynchronous calls." # Checks that CurrentUtcDateTime does not update following an asynchronous call $tasks = @() -$tasks += Invoke-ActivityFunction -FunctionName "DurableActivity" -Input "Seattle" -NoWait +$tasks += Invoke-DurableActivity -FunctionName "DurableActivity" -Input "Seattle" -NoWait # Add-Content -Value $Context.CurrentUtcDateTime -Path $path -$tasks += Invoke-ActivityFunction -FunctionName "DurableActivity" -Input "London" -NoWait +$tasks += Invoke-DurableActivity -FunctionName "DurableActivity" -Input "London" -NoWait # Add-Content -Value $Context.CurrentUtcDateTime -Path $path diff --git a/test/E2E/TestFunctionApp/DurableClient/run.ps1 b/test/E2E/TestFunctionApp/DurableClient/run.ps1 index 53999742..f59af02f 100644 --- a/test/E2E/TestFunctionApp/DurableClient/run.ps1 +++ b/test/E2E/TestFunctionApp/DurableClient/run.ps1 @@ -8,10 +8,10 @@ $ErrorActionPreference = 'Stop' $FunctionName = $Request.Query.FunctionName ?? 'DurableOrchestrator' -$InstanceId = Start-NewOrchestration -FunctionName $FunctionName -InputObject 'Hello' +$InstanceId = Start-DurableOrchestration -FunctionName $FunctionName -InputObject 'Hello' Write-Host "Started orchestration with ID = '$InstanceId'" -$Response = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId +$Response = New-DurableOrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId Push-OutputBinding -Name Response -Value $Response Write-Host "DurableClient completed" diff --git a/test/E2E/TestFunctionApp/DurableClientLegacyNames/function.json b/test/E2E/TestFunctionApp/DurableClientLegacyNames/function.json new file mode 100644 index 00000000..3203d900 --- /dev/null +++ b/test/E2E/TestFunctionApp/DurableClientLegacyNames/function.json @@ -0,0 +1,24 @@ +{ + "bindings": [ + { + "authLevel": "anonymous", + "type": "httpTrigger", + "direction": "in", + "name": "Request", + "methods": [ + "get", + "post" + ] + }, + { + "type": "http", + "direction": "out", + "name": "Response" + }, + { + "name": "starter", + "type": "durableClient", + "direction": "in" + } + ] +} diff --git a/test/E2E/TestFunctionApp/DurableClientLegacyNames/run.ps1 b/test/E2E/TestFunctionApp/DurableClientLegacyNames/run.ps1 new file mode 100644 index 00000000..90c9cc6d --- /dev/null +++ b/test/E2E/TestFunctionApp/DurableClientLegacyNames/run.ps1 @@ -0,0 +1,15 @@ +using namespace System.Net + +param($Request, $TriggerMetadata) + +Write-Host "DurableClientLegacyNames started" + +$ErrorActionPreference = 'Stop' + +$InstanceId = Start-NewOrchestration -FunctionName 'DurableOrchestratorLegacyNames' -InputObject 'Hello' +Write-Host "Started orchestration with ID = '$InstanceId'" + +$Response = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId +Push-OutputBinding -Name Response -Value $Response + +Write-Host "DurableClientLegacyNames completed" diff --git a/test/E2E/TestFunctionApp/DurableOrchestrator/run.ps1 b/test/E2E/TestFunctionApp/DurableOrchestrator/run.ps1 index 8122ad9d..8a9e6df8 100644 --- a/test/E2E/TestFunctionApp/DurableOrchestrator/run.ps1 +++ b/test/E2E/TestFunctionApp/DurableOrchestrator/run.ps1 @@ -10,18 +10,18 @@ Set-DurableCustomStatus -CustomStatus 'Custom status: started' # Function chaining $output = @() -$output += Invoke-ActivityFunction -FunctionName "DurableActivity" -Input "Tokyo" +$output += Invoke-DurableActivity -FunctionName "DurableActivity" -Input "Tokyo" # Fan-out/Fan-in $tasks = @() -$tasks += Invoke-ActivityFunction -FunctionName "DurableActivity" -Input "Seattle" -NoWait -$tasks += Invoke-ActivityFunction -FunctionName "DurableActivity" -Input "London" -NoWait +$tasks += Invoke-DurableActivity -FunctionName "DurableActivity" -Input "Seattle" -NoWait +$tasks += Invoke-DurableActivity -FunctionName "DurableActivity" -Input "London" -NoWait $output += Wait-DurableTask -Task $tasks # Retries $retryOptions = New-DurableRetryOptions -FirstRetryInterval (New-Timespan -Seconds 2) -MaxNumberOfAttempts 5 $inputData = @{ Name = 'Toronto'; StartTime = $Context.CurrentUtcDateTime } -$output += Invoke-ActivityFunction -FunctionName "DurableActivityFlaky" -Input $inputData -RetryOptions $retryOptions +$output += Invoke-DurableActivity -FunctionName "DurableActivityFlaky" -Input $inputData -RetryOptions $retryOptions Set-DurableCustomStatus -CustomStatus 'Custom status: finished' diff --git a/test/E2E/TestFunctionApp/DurableOrchestratorLegacyNames/function.json b/test/E2E/TestFunctionApp/DurableOrchestratorLegacyNames/function.json new file mode 100644 index 00000000..0c950e30 --- /dev/null +++ b/test/E2E/TestFunctionApp/DurableOrchestratorLegacyNames/function.json @@ -0,0 +1,9 @@ +{ + "bindings": [ + { + "name": "Context", + "type": "orchestrationTrigger", + "direction": "in" + } + ] +} diff --git a/test/E2E/TestFunctionApp/DurableOrchestratorLegacyNames/run.ps1 b/test/E2E/TestFunctionApp/DurableOrchestratorLegacyNames/run.ps1 new file mode 100644 index 00000000..feef7bec --- /dev/null +++ b/test/E2E/TestFunctionApp/DurableOrchestratorLegacyNames/run.ps1 @@ -0,0 +1,13 @@ +using namespace System.Net + +param($Context) + +$ErrorActionPreference = 'Stop' + +Write-Host "DurableOrchestratorLegacyNames: started. Input: $($Context.Input)" + +Invoke-ActivityFunction -FunctionName "DurableActivity" -Input "Tokyo" + +Write-Host "DurableOrchestratorLegacyNames: finished." + +return $output diff --git a/test/E2E/TestFunctionApp/DurableOrchestratorWithException/run.ps1 b/test/E2E/TestFunctionApp/DurableOrchestratorWithException/run.ps1 index 01fca0db..9d8ab953 100644 --- a/test/E2E/TestFunctionApp/DurableOrchestratorWithException/run.ps1 +++ b/test/E2E/TestFunctionApp/DurableOrchestratorWithException/run.ps1 @@ -4,6 +4,6 @@ param($Context) $ErrorActionPreference = 'Stop' -Invoke-ActivityFunction -FunctionName 'DurableActivityWithException' -Input 'Name' -ErrorAction Stop +Invoke-DurableActivity -FunctionName 'DurableActivityWithException' -Input 'Name' -ErrorAction Stop 'This should not be returned' diff --git a/test/E2E/TestFunctionApp/DurableTimerClient/run.ps1 b/test/E2E/TestFunctionApp/DurableTimerClient/run.ps1 index 8c359c99..068524ce 100644 --- a/test/E2E/TestFunctionApp/DurableTimerClient/run.ps1 +++ b/test/E2E/TestFunctionApp/DurableTimerClient/run.ps1 @@ -6,10 +6,10 @@ Write-Host "DurableTimerClient started" $ErrorActionPreference = 'Stop' -$InstanceId = Start-NewOrchestration -FunctionName 'DurableTimerOrchestrator' +$InstanceId = Start-DurableOrchestration -FunctionName 'DurableTimerOrchestrator' Write-Host "Started orchestration with ID = '$InstanceId'" -$Response = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId +$Response = New-DurableOrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId Push-OutputBinding -Name Response -Value $Response Write-Host "DurableTimerClient completed" diff --git a/test/E2E/TestFunctionApp/ExternalEventClient/run.ps1 b/test/E2E/TestFunctionApp/ExternalEventClient/run.ps1 index b282db4b..f092ee69 100644 --- a/test/E2E/TestFunctionApp/ExternalEventClient/run.ps1 +++ b/test/E2E/TestFunctionApp/ExternalEventClient/run.ps1 @@ -8,10 +8,10 @@ $ErrorActionPreference = 'Stop' $OrchestratorInputs = @{ FirstDuration = 5; SecondDuration = 60 } -$InstanceId = Start-NewOrchestration -FunctionName 'ExternalEventOrchestrator' -InputObject $OrchestratorInputs +$InstanceId = Start-DurableOrchestration -FunctionName 'ExternalEventOrchestrator' -InputObject $OrchestratorInputs Write-Host "Started orchestration with ID = '$InstanceId'" -$Response = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId +$Response = New-DurableOrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId Push-OutputBinding -Name Response -Value $Response Start-Sleep -Seconds 15