Skip to content

Commit 3ea6d9d

Browse files
authored
Enable PowerShell placeholders (#5831)
1 parent 5433da7 commit 3ea6d9d

File tree

4 files changed

+39
-20
lines changed

4 files changed

+39
-20
lines changed

src/WebJobs.Script/Workers/Rpc/RpcInitializationService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ public class RpcInitializationService : IManagedHostedService
4949
private List<string> _placeholderPoolWhitelistedRuntimes = new List<string>()
5050
{
5151
RpcWorkerConstants.JavaLanguageWorkerName,
52-
RpcWorkerConstants.NodeLanguageWorkerName
52+
RpcWorkerConstants.NodeLanguageWorkerName,
53+
RpcWorkerConstants.PowerShellLanguageWorkerName
5354
};
5455

5556
public RpcInitializationService(IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions, IEnvironment environment, IRpcServer rpcServer, IWebHostRpcWorkerChannelManager rpcWorkerChannelManager, ILogger<RpcInitializationService> logger)

src/WebJobs.Script/Workers/Rpc/WebHostRpcWorkerChannelManager.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,11 @@ private bool UsePlaceholderChannel(string workerRuntime)
134134
{
135135
if (!string.IsNullOrEmpty(workerRuntime))
136136
{
137-
// Special case: node apps must be read-only to use the placeholder mode channel
137+
// Special case: node and PowerShell apps must be read-only to use the placeholder mode channel
138138
// Also cannot use placeholder worker that is targeting ~3 but has backwards compatibility with V2 enabled
139139
// TODO: Remove special casing when resolving https://github.com/Azure/azure-functions-host/issues/4534
140-
if (string.Equals(workerRuntime, RpcWorkerConstants.NodeLanguageWorkerName, StringComparison.OrdinalIgnoreCase))
140+
if (string.Equals(workerRuntime, RpcWorkerConstants.NodeLanguageWorkerName, StringComparison.OrdinalIgnoreCase)
141+
|| string.Equals(workerRuntime, RpcWorkerConstants.PowerShellLanguageWorkerName, StringComparison.OrdinalIgnoreCase))
141142
{
142143
// Use if readonly and not v2 compatible on ~3 extension
143144
return _environment.IsFileSystemReadOnly() && !_environment.IsV2CompatabileOnV3Extension();

test/WebJobs.Script.Tests/Workers/Rpc/RpcInitializationServiceTests.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using System;
@@ -75,6 +75,7 @@ public async Task RpcInitializationService_Initializes_RpcServerAndChannels_Wind
7575
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.JavaLanguageWorkerName), Times.Once);
7676
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PythonLanguageWorkerName), Times.Never);
7777
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.NodeLanguageWorkerName), Times.Never);
78+
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PowerShellLanguageWorkerName), Times.Never);
7879
Assert.Contains("testserver", testRpcServer.Uri.ToString());
7980
await testRpcServer.ShutdownAsync();
8081
}
@@ -92,6 +93,7 @@ public async Task RpcInitializationService_Initializes_RpcServerOnly_Windows_NoP
9293
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.JavaLanguageWorkerName), Times.Never);
9394
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PythonLanguageWorkerName), Times.Never);
9495
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.NodeLanguageWorkerName), Times.Never);
96+
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PowerShellLanguageWorkerName), Times.Never);
9597
Assert.Contains("testserver", testRpcServer.Uri.ToString());
9698
await testRpcServer.ShutdownAsync();
9799
}
@@ -116,6 +118,7 @@ public async Task RpcInitializationService_Initializes_RpcServerAndChannels_Linu
116118
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PythonLanguageWorkerName), Times.Once);
117119
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.NodeLanguageWorkerName), Times.Once);
118120
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.JavaLanguageWorkerName), Times.Never);
121+
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PowerShellLanguageWorkerName), Times.Never);
119122
Assert.Contains("testserver", testRpcServer.Uri.ToString());
120123
await testRpcServer.ShutdownAsync();
121124

@@ -140,6 +143,7 @@ public async Task RpcInitializationService_Does_Not_Initialize_RpcServerAndChann
140143
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PythonLanguageWorkerName), Times.Never);
141144
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.NodeLanguageWorkerName), Times.Never);
142145
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.JavaLanguageWorkerName), Times.Never);
146+
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PowerShellLanguageWorkerName), Times.Never);
143147
Assert.DoesNotContain("testserver", testRpcServer.Uri.ToString());
144148
await testRpcServer.ShutdownAsync();
145149

@@ -166,6 +170,7 @@ public async Task RpcInitializationService_Initializes_RpcServerOnly_LinuxConsum
166170
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PythonLanguageWorkerName), Times.Never);
167171
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.NodeLanguageWorkerName), Times.Never);
168172
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.JavaLanguageWorkerName), Times.Never);
173+
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PowerShellLanguageWorkerName), Times.Never);
169174
Assert.Contains("testserver", testRpcServer.Uri.ToString());
170175
await testRpcServer.ShutdownAsync();
171176

@@ -187,6 +192,7 @@ public async Task RpcInitializationService_Initializes_RpcServerAndChannels_Linu
187192
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PythonLanguageWorkerName), Times.Once);
188193
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.NodeLanguageWorkerName), Times.Once);
189194
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.JavaLanguageWorkerName), Times.Never);
195+
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PowerShellLanguageWorkerName), Times.Never);
190196
Assert.Contains("testserver", testRpcServer.Uri.ToString());
191197
await testRpcServer.ShutdownAsync();
192198
}
@@ -206,6 +212,7 @@ public async Task RpcInitializationService_Initializes_RpcServerOnly_LinuxAppSer
206212
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PythonLanguageWorkerName), Times.Never);
207213
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.NodeLanguageWorkerName), Times.Never);
208214
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.JavaLanguageWorkerName), Times.Never);
215+
_mockLanguageWorkerChannelManager.Verify(m => m.InitializeChannelAsync(RpcWorkerConstants.PowerShellLanguageWorkerName), Times.Never);
209216
Assert.Contains("testserver", testRpcServer.Uri.ToString());
210217
await testRpcServer.ShutdownAsync();
211218
}
@@ -351,6 +358,10 @@ public void ShouldStartStandbyPlaceholderChannels_Returns_ExpectedValue(string p
351358
[InlineData("0", "node", "1234", false)]
352359
[InlineData("1", "node", "", true)]
353360
[InlineData("1", "Node", "", true)]
361+
[InlineData("1", "powershell", "1234", true)]
362+
[InlineData("0", "powershell", "1234", false)]
363+
[InlineData("1", "powershell", "", true)]
364+
[InlineData("1", "Powershell", "", true)]
354365
[InlineData("1", "java", "1234", true)]
355366
[InlineData("0", "java", "1234", false)]
356367
[InlineData("0", "JAVA", "1234", false)]

test/WebJobs.Script.Tests/Workers/Rpc/WebHostRpcWorkerChannelManagerTests.cs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -160,17 +160,19 @@ public async Task ShutdownStandyChannels_WorkerRuntime_Node_Set()
160160
}
161161

162162
[Theory]
163-
[InlineData("nOde")]
164-
[InlineData("Node")]
165-
public async Task SpecializeAsync_Node_ReadOnly_KeepsProcessAlive(string runtime)
163+
[InlineData("nOde", RpcWorkerConstants.NodeLanguageWorkerName)]
164+
[InlineData("Node", RpcWorkerConstants.NodeLanguageWorkerName)]
165+
[InlineData("PowerShell", RpcWorkerConstants.PowerShellLanguageWorkerName)]
166+
[InlineData("pOwerShell", RpcWorkerConstants.PowerShellLanguageWorkerName)]
167+
public async Task SpecializeAsync_ReadOnly_KeepsProcessAlive(string runtime, string languageWorkerName)
166168
{
167169
var testMetricsLogger = new TestMetricsLogger();
168170
_testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, runtime);
169171
_testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteZipDeployment, "1");
170172

171173
_rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor);
172174

173-
IRpcWorkerChannel nodeWorkerChannel = CreateTestChannel(RpcWorkerConstants.NodeLanguageWorkerName);
175+
IRpcWorkerChannel workerChannel = CreateTestChannel(languageWorkerName);
174176

175177
await _rpcWorkerChannelManager.SpecializeAsync();
176178
Assert.True(testMetricsLogger.EventsBegan.Contains(MetricEventNames.SpecializationScheduleShutdownStandbyChannels)
@@ -182,8 +184,8 @@ public async Task SpecializeAsync_Node_ReadOnly_KeepsProcessAlive(string runtime
182184
Assert.True(functionLoadLogs.Count() == 1);
183185

184186
// Verify channel
185-
var initializedChannel = await _rpcWorkerChannelManager.GetChannelAsync(RpcWorkerConstants.NodeLanguageWorkerName);
186-
Assert.Equal(nodeWorkerChannel, initializedChannel);
187+
var initializedChannel = await _rpcWorkerChannelManager.GetChannelAsync(languageWorkerName);
188+
Assert.Equal(workerChannel, initializedChannel);
187189
}
188190

189191
[Fact]
@@ -238,17 +240,19 @@ public async Task SpecializeAsync_Java_ReadOnly_KeepsProcessAlive()
238240
Assert.Equal(javaWorkerChannel, initializedChannel);
239241
}
240242

241-
[Fact]
242-
public async Task SpecializeAsync_Node_NotReadOnly_KillsProcess()
243+
[Theory]
244+
[InlineData(RpcWorkerConstants.NodeLanguageWorkerName)]
245+
[InlineData(RpcWorkerConstants.PowerShellLanguageWorkerName)]
246+
public async Task SpecializeAsync_NotReadOnly_KillsProcess(string languageWorkerName)
243247
{
244248
var testMetricsLogger = new TestMetricsLogger();
245-
_testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, RpcWorkerConstants.NodeLanguageWorkerName);
249+
_testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, languageWorkerName);
246250
// This is an invalid setting configuration, but just to show that run from zip is NOT set
247251
_testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteZipDeployment, "0");
248252

249253
_rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor);
250254

251-
IRpcWorkerChannel nodeWorkerChannel = CreateTestChannel(RpcWorkerConstants.NodeLanguageWorkerName);
255+
IRpcWorkerChannel workerChannel = CreateTestChannel(languageWorkerName);
252256

253257
await _rpcWorkerChannelManager.SpecializeAsync();
254258

@@ -257,21 +261,23 @@ public async Task SpecializeAsync_Node_NotReadOnly_KillsProcess()
257261
Assert.True(traces.Count() == 0);
258262

259263
// Verify channel
260-
var initializedChannel = await _rpcWorkerChannelManager.GetChannelAsync(RpcWorkerConstants.NodeLanguageWorkerName);
264+
var initializedChannel = await _rpcWorkerChannelManager.GetChannelAsync(languageWorkerName);
261265
Assert.Null(initializedChannel);
262266
}
263267

264-
[Fact]
265-
public async Task SpecializeAsync_Node_V2CompatibilityWithV3Extension_KillsProcess()
268+
[Theory]
269+
[InlineData(RpcWorkerConstants.NodeLanguageWorkerName)]
270+
[InlineData(RpcWorkerConstants.PowerShellLanguageWorkerName)]
271+
public async Task SpecializeAsync_Node_V2CompatibilityWithV3Extension_KillsProcess(string languageWorkerName)
266272
{
267273
var testMetricsLogger = new TestMetricsLogger();
268-
_testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, RpcWorkerConstants.NodeLanguageWorkerName);
274+
_testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, languageWorkerName);
269275
_testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.FunctionsV2CompatibilityModeKey, "true");
270276
_testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.FunctionsExtensionVersion, "~3");
271277

272278
_rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor);
273279

274-
IRpcWorkerChannel nodeWorkerChannel = CreateTestChannel(RpcWorkerConstants.NodeLanguageWorkerName);
280+
IRpcWorkerChannel workerChannel = CreateTestChannel(languageWorkerName);
275281

276282
await _rpcWorkerChannelManager.SpecializeAsync();
277283

@@ -280,7 +286,7 @@ public async Task SpecializeAsync_Node_V2CompatibilityWithV3Extension_KillsProce
280286
Assert.True(traces.Count() == 0);
281287

282288
// Verify channel
283-
var initializedChannel = await _rpcWorkerChannelManager.GetChannelAsync(RpcWorkerConstants.NodeLanguageWorkerName);
289+
var initializedChannel = await _rpcWorkerChannelManager.GetChannelAsync(languageWorkerName);
284290
Assert.Null(initializedChannel);
285291
}
286292

0 commit comments

Comments
 (0)