Skip to content

Commit 1c5ff1a

Browse files
committed
Add Version parameter to Start-DurableOrchestration and Invoke-SubOrchestrator
1 parent 0992233 commit 1c5ff1a

20 files changed

+219
-22
lines changed

src/AzureFunctions.PowerShell.Durable.SDK.psm1

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,11 @@ function Start-DurableOrchestration {
100100

101101
[Parameter(
102102
ValueFromPipelineByPropertyName=$true)]
103-
[string] $InstanceId
103+
[string] $InstanceId,
104+
105+
[Parameter(
106+
ValueFromPipelineByPropertyName=$true)]
107+
[string] $Version
104108
)
105109

106110
$ErrorActionPreference = 'Stop'
@@ -126,6 +130,12 @@ function Start-DurableOrchestration {
126130
$UriTemplate.Replace('{functionName}', $FunctionName).Replace('[/{instanceId}]', "/$InstanceId")
127131
}
128132

133+
# Add version parameter to query string if provided
134+
if ($Version) {
135+
$separator = if ($Uri.Contains('?')) { '&' } else { '?' }
136+
$Uri += "$separator" + "version=$([System.Web.HttpUtility]::UrlEncode($Version))"
137+
}
138+
129139
$Body = $InputObject | ConvertTo-Json -Compress -Depth 100
130140

131141
$null = Invoke-RestMethod -Uri $Uri -Method 'POST' -ContentType 'application/json' -Body $Body -Headers $headers

src/DurableEngine/Actions/CallSubOrchestratorAction.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,18 @@ internal class CallSubOrchestratorAction : OrchestrationAction
2222
/// </summary>
2323
public readonly object Input;
2424

25-
internal CallSubOrchestratorAction(string functionName, object input, string instanceId)
25+
/// <summary>
26+
/// The version of the sub-orchestrator function.
27+
/// </summary>
28+
public readonly string Version;
29+
30+
internal CallSubOrchestratorAction(string functionName, object input, string instanceId, string version)
2631
: base(ActionType.CallSubOrchestrator)
2732
{
2833
FunctionName = functionName;
2934
Input = input;
3035
InstanceId = instanceId;
36+
Version = version;
3137
}
3238
}
3339
}

src/DurableEngine/Actions/CallSubOrchestratorWithRetryAction.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,19 @@ internal class CallSubOrchestratorWithRetryAction : OrchestrationAction
2929
/// </summary>
3030
public readonly Dictionary<string, object> RetryOptions;
3131

32-
internal CallSubOrchestratorWithRetryAction(string functionName, object input, string instanceId, RetryPolicy retryOptions)
32+
/// <summary>
33+
/// The version of the sub-orchestrator function.
34+
/// </summary>
35+
public readonly string Version;
36+
37+
internal CallSubOrchestratorWithRetryAction(string functionName, object input, string instanceId, RetryPolicy retryOptions, string version)
3338
: base(ActionType.CallSubOrchestratorWithRetry)
3439
{
3540
FunctionName = functionName;
3641
InstanceId = instanceId;
3742
Input = input;
3843
RetryOptions = retryOptions.RetryPolicyDictionary;
44+
Version = version;
3945
}
4046
}
4147
}

src/DurableEngine/DurableEngine.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.DurableTask.Client" Version="1.11.0" />
11-
<PackageReference Include="Microsoft.DurableTask.Worker" Version="1.11.0" />
10+
<PackageReference Include="Microsoft.DurableTask.Client" Version="1.15.1" />
11+
<PackageReference Include="Microsoft.DurableTask.Worker" Version="1.15.1" />
1212
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.4.10" PrivateAssets="all" />
1313
</ItemGroup>
1414
</Project>

src/DurableEngine/Tasks/SubOrchestratorTask.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,22 @@ public class SubOrchestratorTask : DurableTask
2020

2121
private RetryPolicy RetryOptions { get; }
2222

23+
internal string Version { get; }
24+
2325
public SubOrchestratorTask(
2426
string functionName,
2527
string instanceId,
2628
object functionInput,
2729
RetryPolicy retryOptions,
30+
string version,
2831
SwitchParameter noWait,
2932
Hashtable privateData) : base(noWait, privateData)
3033
{
3134
FunctionName = functionName;
3235
InstanceId = instanceId;
3336
Input = functionInput;
3437
RetryOptions = retryOptions;
38+
Version = version;
3539
}
3640

3741
internal override Task<object> CreateDTFxTask()
@@ -45,14 +49,19 @@ internal override Task<object> CreateDTFxTask()
4549
? taskOptions :
4650
taskOptions.WithInstanceId(InstanceId);
4751

48-
return DTFxContext.CallSubOrchestratorAsync<object>(FunctionName, Input, taskOptions);
52+
var subOrchestrationOptions = new SubOrchestrationOptions(taskOptions, InstanceId)
53+
{
54+
Version = this.Version
55+
};
56+
57+
return DTFxContext.CallSubOrchestratorAsync<object>(FunctionName, Input, subOrchestrationOptions);
4958
}
5059

5160
internal override OrchestrationAction CreateOrchestrationAction()
5261
{
5362
return RetryOptions == null
54-
? new CallSubOrchestratorAction(FunctionName, Input, InstanceId)
55-
: new CallSubOrchestratorWithRetryAction(FunctionName, Input, InstanceId, RetryOptions);
63+
? new CallSubOrchestratorAction(FunctionName, Input, InstanceId, Version)
64+
: new CallSubOrchestratorWithRetryAction(FunctionName, Input, InstanceId, RetryOptions, Version);
5665
}
5766
}
5867
}

src/DurableSDK/Commands/APIs/InvokeSubOrchestratorCommand.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ public class InvokeSubOrchestratorCommand : DurableSDKCmdlet
4343
[ValidateNotNull]
4444
public RetryPolicy RetryOptions { get; set; }
4545

46+
/// <summary>
47+
/// Version of the SubOrchestrator to invoke.
48+
/// </summary>
49+
[Parameter]
50+
[ValidateNotNull]
51+
public string Version { get; set; }
52+
4653
/// <summary>
4754
/// If provided, the Task will block and be scheduled immediately.
4855
/// Otherwise, a Task object is returned and the Task is not scheduled yet.
@@ -53,7 +60,7 @@ public class InvokeSubOrchestratorCommand : DurableSDKCmdlet
5360
internal override DurableTask CreateDurableTask()
5461
{
5562
var privateData = (Hashtable)MyInvocation.MyCommand.Module.PrivateData;
56-
SubOrchestratorTask task = new SubOrchestratorTask(FunctionName, InstanceId, Input, RetryOptions, NoWait, privateData);
63+
SubOrchestratorTask task = new SubOrchestratorTask(FunctionName, InstanceId, Input, RetryOptions, Version, NoWait, privateData);
5764
return task;
5865
}
5966
}

src/Help/Invoke-DurableSubOrchestrator.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Invokes a sub-orchestrator function.
1414
## SYNTAX
1515

1616
```
17-
Invoke-DurableSubOrchestrator -FunctionName <String> [-InstanceId <String>] [-Input <Object>] [-RetryOptions <RetryPolicy>] [-NoWait] [<CommonParameters>]
17+
Invoke-DurableSubOrchestrator -FunctionName <String> [-InstanceId <String>] [-Input <Object>] [-RetryOptions <RetryPolicy>] [-Version <String>] [-NoWait] [<CommonParameters>]
1818
```
1919

2020
## DESCRIPTION
@@ -46,6 +46,15 @@ Write-Host "Sub-orchestrator completed with result: $batchResult"
4646

4747
This example shows how to invoke a sub-orchestrator function asynchronously using -NoWait, which returns a task object that can be awaited later.
4848

49+
### Example 3 - Specifying a version
50+
51+
```powershell
52+
$result = Invoke-DurableSubOrchestrator -FunctionName "ChildOrchestrator" -Version "2.0" -Input @{ ProcessId = "proc456" }
53+
Write-Host "Sub-orchestrator (version 2.0) completed with result: $result"
54+
```
55+
56+
This example shows how to invoke a sub-orchestrator with a specific version, overriding the default version configured in host.json.
57+
4958
## PARAMETERS
5059

5160
### -FunctionName
@@ -96,6 +105,22 @@ Accept pipeline input: False
96105
Accept wildcard characters: False
97106
```
98107
108+
### -Version
109+
110+
An optional version string for the sub-orchestrator function. When specified, this version overrides the default version configured in host.json for this specific sub-orchestrator invocation. This allows you to invoke specific versions of orchestrator functions.
111+
112+
```yaml
113+
Type: String
114+
Parameter Sets: (All)
115+
Aliases:
116+
117+
Required: False
118+
Position: Named
119+
Default value: None
120+
Accept pipeline input: False
121+
Accept wildcard characters: False
122+
```
123+
99124
### -NoWait
100125
101126
When specified, the cmdlet returns a task object immediately without waiting for completion. By default, the cmdlet blocks and waits for the sub-orchestrator to complete before returning the result.
@@ -152,6 +177,7 @@ Returns the result of the sub-orchestrator execution by default. If -NoWait is s
152177
- Use the -NoWait parameter when you need to invoke multiple sub-orchestrators concurrently.
153178
- Sub-orchestrators inherit the fault-tolerance and replay characteristics of the parent orchestration.
154179
- The sub-orchestrator function name must match a function defined in your Azure Functions app with an orchestration trigger.
180+
- The -Version parameter allows you to invoke specific versions of orchestrator functions, overriding the default version from host.json.
155181
- Consider using sub-orchestrators to break down complex workflows into manageable, reusable components.
156182
157183
## RELATED LINKS

src/Help/Start-DurableOrchestration.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Start a durable orchestration.
1414
## SYNTAX
1515

1616
```
17-
Start-DurableOrchestration [-FunctionName] <String> [[-InputObject] <Object>] [-DurableClient <Object>] [-InstanceId <String>] [<CommonParameters>]
17+
Start-DurableOrchestration [-FunctionName] <String> [[-InputObject] <Object>] [-DurableClient <Object>] [-InstanceId <String>] [-Version <String>] [<CommonParameters>]
1818
```
1919

2020
## DESCRIPTION
@@ -99,6 +99,24 @@ Accept pipeline input: True (ByPropertyName)
9999
Accept wildcard characters: False
100100
```
101101
102+
### -Version
103+
104+
Optional orchestration version.
105+
The provided value will be available as `$Context.Version` within the orchestrator function context.
106+
If not specified, the default version specified by the `defaultVersion` property in the Function app's host.json will be used.
107+
108+
```yaml
109+
Type: String
110+
Parameter Sets: (All)
111+
Aliases:
112+
113+
Required: False
114+
Position: Named
115+
Default value: None
116+
Accept pipeline input: True (ByPropertyName)
117+
Accept wildcard characters: False
118+
```
119+
102120
### CommonParameters
103121

104122
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -ProgressAction, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
@@ -117,6 +135,10 @@ You can pipe objects to the -InputObject parameter to provide input data for the
117135

118136
You can pipe strings to the -InstanceId parameter to specify a custom instance ID for the orchestration.
119137

138+
### System.String (Version)
139+
140+
You can pipe strings to the -Version parameter to specify a version for the orchestration function.
141+
120142
## OUTPUTS
121143

122144
### System.String

test/E2E/AzureFunctions.PowerShell.Durable.SDK.E2E/ActivityTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public async Task ActivityCanHaveQueueBinding()
2323
Assert.Equal(HttpStatusCode.Accepted, initialResponse.StatusCode);
2424

2525
var initialResponseBodyString = await initialResponse.Content.ReadAsStringAsync();
26-
dynamic initialResponseBody = JsonConvert.DeserializeObject(initialResponseBodyString);
26+
dynamic initialResponseBody = JsonConvert.DeserializeObject(initialResponseBodyString)!;
2727
var statusQueryGetUri = (string)initialResponseBody.statusQueryGetUri;
2828

2929
var startTime = DateTime.UtcNow;
@@ -41,7 +41,7 @@ public async Task ActivityCanHaveQueueBinding()
4141
{
4242
if (DateTime.UtcNow > startTime + _orchestrationCompletionTimeout)
4343
{
44-
Assert.True(false, $"The orchestration has not completed after {_orchestrationCompletionTimeout}");
44+
Assert.Fail($"The orchestration has not completed after {_orchestrationCompletionTimeout}");
4545
}
4646
await Task.Delay(TimeSpan.FromSeconds(2));
4747
break;
@@ -56,7 +56,7 @@ public async Task ActivityCanHaveQueueBinding()
5656
}
5757

5858
default:
59-
Assert.True(false, $"Unexpected orchestration status code: {statusResponse.StatusCode}");
59+
Assert.Fail($"Unexpected orchestration status code: {statusResponse.StatusCode}");
6060
break;
6161
}
6262
}

test/E2E/AzureFunctions.PowerShell.Durable.SDK.E2E/Constants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public static class Constants
1313
public static class Queue
1414
{
1515
public static string QueueName = "outqueue";
16-
public static string StorageConnectionStringSetting = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
16+
public static string StorageConnectionStringSetting = Environment.GetEnvironmentVariable("AzureWebJobsStorage") ?? "AzureWebJobsStorage placeholder";
1717
public static string OutputBindingName = "test-output-ps";
1818
public static string InputBindingName = "test-input-ps";
1919
}

0 commit comments

Comments
 (0)