Skip to content

Commit 61aabba

Browse files
authored
Refactor and clean up based on the dependency management changes (Azure#194)
1 parent 52e5c4b commit 61aabba

File tree

4 files changed

+169
-177
lines changed

4 files changed

+169
-177
lines changed

src/DependencyManagement/DependencyManager.cs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,25 @@
33
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
44
//
55

6-
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
76
using System;
87
using System.Text;
98
using System.Text.RegularExpressions;
109
using System.Collections;
1110
using System.Collections.Generic;
1211
using System.IO;
1312
using System.Linq;
13+
using System.Threading.Tasks;
1414
using Microsoft.Azure.Functions.PowerShellWorker.PowerShell;
1515
using Microsoft.Azure.Functions.PowerShellWorker.Utility;
16-
using LogLevel = Microsoft.Azure.WebJobs.Script.Grpc.Messages.RpcLog.Types.Level;
1716
using Microsoft.Azure.Functions.PowerShellWorker.Messaging;
17+
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
18+
using LogLevel = Microsoft.Azure.WebJobs.Script.Grpc.Messages.RpcLog.Types.Level;
1819

1920
namespace Microsoft.Azure.Functions.PowerShellWorker.DependencyManagement
2021
{
2122
using System.Management.Automation;
2223
using System.Management.Automation.Language;
2324
using System.Management.Automation.Runspaces;
24-
using System.Threading.Tasks;
2525

2626
internal class DependencyManager
2727
{
@@ -122,18 +122,9 @@ private void ProcessDependencies(RpcLogger rpcLogger)
122122
try
123123
{
124124
_dependencyError = null;
125-
var initialSessionState = InitialSessionState.CreateDefault();
126-
initialSessionState.ThreadOptions = PSThreadOptions.UseCurrentThread;
127-
initialSessionState.EnvironmentVariables.Add(new SessionStateVariableEntry("PSModulePath", FunctionLoader.FunctionModulePath, null));
128-
// Setting the execution policy on macOS and Linux throws an exception so only update it on Windows
129-
if (Platform.IsWindows)
130-
{
131-
initialSessionState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;
132-
}
133-
134-
using (PowerShell powerShellInstance = PowerShell.Create(initialSessionState))
125+
using (PowerShell pwsh = PowerShell.Create(Utils.SingletonISS.Value))
135126
{
136-
InstallFunctionAppDependencies(powerShellInstance, rpcLogger);
127+
InstallFunctionAppDependencies(pwsh, rpcLogger);
137128
}
138129
}
139130
catch (Exception e)
@@ -152,6 +143,11 @@ private void ProcessDependencies(RpcLogger rpcLogger)
152143
/// </summary>
153144
internal void Initialize(FunctionLoadRequest request)
154145
{
146+
if (!request.ManagedDependencyEnabled)
147+
{
148+
return;
149+
}
150+
155151
try
156152
{
157153
// Resolve the FunctionApp root path.

src/PowerShell/PowerShellManager.cs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,8 @@ internal PowerShellManager(ILogger logger)
5252
throw new InvalidOperationException(PowerShellWorkerStrings.FunctionAppRootNotResolved);
5353
}
5454

55-
var initialSessionState = InitialSessionState.CreateDefault();
56-
initialSessionState.ThreadOptions = PSThreadOptions.UseCurrentThread;
57-
initialSessionState.EnvironmentVariables.Add(
58-
new SessionStateVariableEntry("PSModulePath", FunctionLoader.FunctionModulePath, null));
59-
60-
// Setting the execution policy on macOS and Linux throws an exception so only update it on Windows
61-
if(Platform.IsWindows)
62-
{
63-
// This sets the execution policy on Windows to Unrestricted which is required to run the user's function scripts on
64-
// Windows client versions. This is needed if a user is testing their function locally with the func CLI
65-
initialSessionState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;
66-
}
67-
6855
_logger = logger;
69-
_pwsh = PowerShell.Create(initialSessionState);
56+
_pwsh = PowerShell.Create(Utils.SingletonISS.Value);
7057

7158
// Setup Stream event listeners
7259
var streamHandler = new StreamHandler(logger);

src/RequestProcessor.cs

Lines changed: 30 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ internal class RequestProcessor
2525
private readonly PowerShellManagerPool _powershellPool;
2626
private readonly DependencyManager _dependencyManager;
2727

28-
// Holds the exception if an issue is encountered while installing the function app dependencies
29-
// or while initializing PowerShell.
28+
// Holds the exception if an issue is encountered while processing the function app dependencies.
3029
private Exception _initTerminatingError;
3130

3231
// Indicate whether the FunctionApp has been initialized.
@@ -167,7 +166,11 @@ internal StreamingMessage ProcessFunctionLoadRequest(StreamingMessage request)
167166
try
168167
{
169168
_isFunctionAppInitialized = true;
170-
InitializeForFunctionApp(request);
169+
_dependencyManager.Initialize(functionLoadRequest);
170+
171+
// Setup the FunctionApp root path and module path.
172+
FunctionLoader.SetupWellKnownPaths(functionLoadRequest);
173+
_dependencyManager.ProcessDependencyDownload(_msgStream, request);
171174
}
172175
catch (Exception e)
173176
{
@@ -200,15 +203,12 @@ internal StreamingMessage ProcessFunctionLoadRequest(StreamingMessage request)
200203
/// </summary>
201204
internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)
202205
{
203-
AzFunctionInfo functionInfo = null;
204-
PowerShellManager psManager = null;
206+
Exception error = null;
205207

206208
try
207209
{
208-
if (_dependencyManager.DependencyDownloadTask != null
209-
&& (_dependencyManager.DependencyDownloadTask.Status != TaskStatus.Canceled
210-
|| _dependencyManager.DependencyDownloadTask.Status != TaskStatus.Faulted
211-
|| _dependencyManager.DependencyDownloadTask.Status != TaskStatus.RanToCompletion))
210+
if (_dependencyManager.DependencyDownloadTask != null &&
211+
!_dependencyManager.DependencyDownloadTask.IsCompleted)
212212
{
213213
var rpcLogger = new RpcLogger(_msgStream);
214214
rpcLogger.SetContext(request.RequestId, request.InvocationRequest?.InvocationId);
@@ -218,43 +218,42 @@ internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)
218218

219219
if (_dependencyManager.DependencyError != null)
220220
{
221-
StreamingMessage response = NewStreamingMessageTemplate(request.RequestId,
222-
StreamingMessage.ContentOneofCase.InvocationResponse,
223-
out StatusResult status);
224-
status.Status = StatusResult.Types.Status.Failure;
225-
status.Exception = _dependencyManager.DependencyError.ToRpcException();
226-
response.InvocationResponse.InvocationId = request.InvocationRequest.InvocationId;
227-
return response;
228-
}
229-
230-
functionInfo = _functionLoader.GetFunctionInfo(request.InvocationRequest.FunctionId);
231-
psManager = _powershellPool.CheckoutIdleWorker(request, functionInfo);
232-
233-
if (_powershellPool.UpperBound == 1)
234-
{
235-
// When the concurrency upper bound is 1, we can handle only one invocation at a time anyways,
236-
// so it's better to just do it on the current thread to reduce the required synchronization.
237-
ProcessInvocationRequestImpl(request, functionInfo, psManager);
221+
error = _dependencyManager.DependencyError;
238222
}
239223
else
240224
{
241-
// When the concurrency upper bound is more than 1, we have to handle the invocation in a worker
242-
// thread, so multiple invocations can make progress at the same time, even though by time-sharing.
243-
Task.Run(() => ProcessInvocationRequestImpl(request, functionInfo, psManager));
225+
AzFunctionInfo functionInfo = _functionLoader.GetFunctionInfo(request.InvocationRequest.FunctionId);
226+
PowerShellManager psManager = _powershellPool.CheckoutIdleWorker(request, functionInfo);
227+
228+
if (_powershellPool.UpperBound == 1)
229+
{
230+
// When the concurrency upper bound is 1, we can handle only one invocation at a time anyways,
231+
// so it's better to just do it on the current thread to reduce the required synchronization.
232+
ProcessInvocationRequestImpl(request, functionInfo, psManager);
233+
}
234+
else
235+
{
236+
// When the concurrency upper bound is more than 1, we have to handle the invocation in a worker
237+
// thread, so multiple invocations can make progress at the same time, even though by time-sharing.
238+
Task.Run(() => ProcessInvocationRequestImpl(request, functionInfo, psManager));
239+
}
244240
}
245241
}
246242
catch (Exception e)
247243
{
248-
_powershellPool.ReclaimUsedWorker(psManager);
244+
error = e;
245+
}
249246

247+
if (error != null)
248+
{
250249
StreamingMessage response = NewStreamingMessageTemplate(
251250
request.RequestId,
252251
StreamingMessage.ContentOneofCase.InvocationResponse,
253252
out StatusResult status);
254253

255254
response.InvocationResponse.InvocationId = request.InvocationRequest.InvocationId;
256255
status.Status = StatusResult.Types.Status.Failure;
257-
status.Exception = e.ToRpcException();
256+
status.Exception = error.ToRpcException();
258257

259258
return response;
260259
}
@@ -314,22 +313,6 @@ internal StreamingMessage ProcessFunctionEnvironmentReloadRequest(StreamingMessa
314313

315314
#region Helper_Methods
316315

317-
/// <summary>
318-
/// Initialize the worker based on the FunctionApp that the worker will deal with.
319-
/// </summary>
320-
private void InitializeForFunctionApp(StreamingMessage request)
321-
{
322-
var functionLoadRequest = request.FunctionLoadRequest;
323-
if (functionLoadRequest.ManagedDependencyEnabled)
324-
{
325-
_dependencyManager.Initialize(functionLoadRequest);
326-
}
327-
328-
// Setup the FunctionApp root path and module path.
329-
FunctionLoader.SetupWellKnownPaths(functionLoadRequest);
330-
_dependencyManager.ProcessDependencyDownload(_msgStream, request);
331-
}
332-
333316
/// <summary>
334317
/// Create an object of 'StreamingMessage' as a template, for further update.
335318
/// </summary>

0 commit comments

Comments
 (0)