Skip to content

Commit c4fe842

Browse files
Populate language worker metadata in init response (#884)
* Populate language worker metadata * Continue to defer the worker initialization until the first FunctionLoadRequest
1 parent 28585cc commit c4fe842

File tree

3 files changed

+46
-10
lines changed

3 files changed

+46
-10
lines changed

src/RequestProcessor.cs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ namespace Microsoft.Azure.Functions.PowerShellWorker
2020
{
2121
using System.Diagnostics;
2222
using LogLevel = Microsoft.Azure.WebJobs.Script.Grpc.Messages.RpcLog.Types.Level;
23+
using System.Runtime.InteropServices;
2324

2425
internal class RequestProcessor
2526
{
2627
private readonly MessagingStream _msgStream;
2728
private readonly System.Management.Automation.PowerShell _firstPwshInstance;
2829
private readonly PowerShellManagerPool _powershellPool;
2930
private DependencyManager _dependencyManager;
31+
private string _pwshVersion;
3032

3133
// Holds the exception if an issue is encountered while processing the function app dependencies.
3234
private Exception _initTerminatingError;
@@ -37,11 +39,12 @@ internal class RequestProcessor
3739
private Dictionary<StreamingMessage.ContentOneofCase, Func<StreamingMessage, StreamingMessage>> _requestHandlers =
3840
new Dictionary<StreamingMessage.ContentOneofCase, Func<StreamingMessage, StreamingMessage>>();
3941

40-
internal RequestProcessor(MessagingStream msgStream, System.Management.Automation.PowerShell firstPwshInstance)
42+
internal RequestProcessor(MessagingStream msgStream, System.Management.Automation.PowerShell firstPwshInstance, string pwshVersion)
4143
{
4244
_msgStream = msgStream;
4345
_firstPwshInstance = firstPwshInstance;
4446
_powershellPool = new PowerShellManagerPool(() => new RpcLogger(msgStream));
47+
_pwshVersion = pwshVersion;
4548

4649
// Host sends capabilities/init data to worker
4750
_requestHandlers.Add(StreamingMessage.ContentOneofCase.WorkerInitRequest, ProcessWorkerInitRequest);
@@ -95,6 +98,9 @@ internal async Task ProcessRequestLoop()
9598

9699
internal StreamingMessage ProcessWorkerInitRequest(StreamingMessage request)
97100
{
101+
var stopwatch = new Stopwatch();
102+
stopwatch.Start();
103+
98104
var workerInitRequest = request.WorkerInitRequest;
99105
Environment.SetEnvironmentVariable("AZUREPS_HOST_ENVIRONMENT", $"AzureFunctions/{workerInitRequest.HostVersion}");
100106
Environment.SetEnvironmentVariable("POWERSHELL_DISTRIBUTION_CHANNEL", $"Azure-Functions:{workerInitRequest.HostVersion}");
@@ -117,6 +123,22 @@ internal StreamingMessage ProcessWorkerInitRequest(StreamingMessage request)
117123
RemoteSessionNamedPipeServer.CreateCustomNamedPipeServer(pipeName);
118124
}
119125

126+
try
127+
{
128+
var rpcLogger = new RpcLogger(_msgStream);
129+
rpcLogger.SetContext(request.RequestId, null);
130+
131+
response.WorkerInitResponse.WorkerMetadata = GetWorkerMetadata(_pwshVersion);
132+
133+
rpcLogger.Log(isUserOnlyLog: false, LogLevel.Trace, string.Format(PowerShellWorkerStrings.WorkerInitCompleted, stopwatch.ElapsedMilliseconds));
134+
}
135+
catch (Exception e)
136+
{
137+
status.Status = StatusResult.Types.Status.Failure;
138+
status.Exception = e.ToRpcException();
139+
return response;
140+
}
141+
120142
return response;
121143
}
122144

@@ -180,11 +202,10 @@ internal StreamingMessage ProcessFunctionLoadRequest(StreamingMessage request)
180202
return response;
181203
}
182204

183-
// Ideally, the initialization should happen when processing 'WorkerInitRequest', however, the 'WorkerInitRequest'
184-
// message doesn't provide information about the FunctionApp. That information is not available until the first
185-
// 'FunctionLoadRequest' comes in. Therefore, we run initialization here.
186-
// Also, we receive a FunctionLoadRequest when a proxy is configured. Proxies don't have the Metadata.Directory set
187-
// which would cause initialization issues with the PSModulePath. Since they don't have that set, we skip over them.
205+
// Ideally, the initialization should happen when processing 'WorkerInitRequest'. However, we defer the initialization
206+
// until the first 'FunctionLoadRequest' which contains the information about whether Managed Dependencies is enabled for the function app,
207+
// and if it is, we add the Managed Dependencies path to the PSModulePath.
208+
// Also, we receive a FunctionLoadRequest when a proxy is configured. This is just a no-op on the worker size, so we skip over them.
188209
if (!_isFunctionAppInitialized && !functionLoadRequest.Metadata.IsProxy)
189210
{
190211
try
@@ -519,6 +540,17 @@ private void SetupAppRootPathAndModulePath(FunctionLoadRequest functionLoadReque
519540
.InvokeAndClearCommands();
520541
}
521542

543+
private WorkerMetadata GetWorkerMetadata(string pwshVersion)
544+
{
545+
var data = new WorkerMetadata();
546+
data.WorkerBitness = RuntimeInformation.OSArchitecture.ToString();
547+
data.WorkerVersion = typeof(Worker).Assembly.GetName().Version.ToString();
548+
data.RuntimeVersion = pwshVersion;
549+
data.RuntimeName = "powershell";
550+
551+
return data;
552+
}
553+
522554
#endregion
523555
}
524556
}

src/Worker.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,12 @@ public async static Task Main(string[] args)
4040
// This PowerShell instance is shared by the first PowerShellManager instance created in the pool,
4141
// and the dependency manager (used to download dependent modules if needed).
4242
var firstPowerShellInstance = Utils.NewPwshInstance();
43-
LogPowerShellVersion(firstPowerShellInstance);
43+
var pwshVersion = Utils.GetPowerShellVersion(firstPowerShellInstance);
44+
LogPowerShellVersion(pwshVersion);
4445
WarmUpPowerShell(firstPowerShellInstance);
4546

4647
var msgStream = new MessagingStream(arguments.Host, arguments.Port);
47-
var requestProcessor = new RequestProcessor(msgStream, firstPowerShellInstance);
48+
var requestProcessor = new RequestProcessor(msgStream, firstPowerShellInstance, pwshVersion);
4849

4950
// Send StartStream message
5051
var startedMessage = new StreamingMessage()
@@ -75,9 +76,9 @@ private static void WarmUpPowerShell(System.Management.Automation.PowerShell fir
7576
.InvokeAndClearCommands();
7677
}
7778

78-
private static void LogPowerShellVersion(System.Management.Automation.PowerShell pwsh)
79+
private static void LogPowerShellVersion(string pwshVersion)
7980
{
80-
var message = string.Format(PowerShellWorkerStrings.PowerShellVersion, Utils.GetPowerShellVersion(pwsh));
81+
var message = string.Format(PowerShellWorkerStrings.PowerShellVersion, pwshVersion);
8182
RpcLogger.WriteSystemLog(LogLevel.Information, message);
8283
}
8384
}

src/resources/PowerShellWorkerStrings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,4 +352,7 @@
352352
<data name="DependencySnapshotDoesNotContainAcceptableModuleVersions" xml:space="preserve">
353353
<value>Dependency snapshot '{0}' does not contain acceptable module versions.</value>
354354
</data>
355+
<data name="WorkerInitCompleted" xml:space="preserve">
356+
<value>Worker init request completed in {0} ms.</value>
357+
</data>
355358
</root>

0 commit comments

Comments
 (0)