18
18
19
19
namespace Microsoft . Azure . Functions . PowerShellWorker
20
20
{
21
+ using Microsoft . Azure . Functions . PowerShellWorker . WorkerIndexing ;
22
+ using Microsoft . PowerShell ;
21
23
using System . Diagnostics ;
24
+ using System . Text . Json ;
22
25
using LogLevel = Microsoft . Azure . WebJobs . Script . Grpc . Messages . RpcLog . Types . Level ;
23
26
24
27
internal class RequestProcessor
@@ -66,6 +69,8 @@ internal RequestProcessor(MessagingStream msgStream, System.Management.Automatio
66
69
// If an invocation is cancelled, host will receive an invocation response with status cancelled.
67
70
_requestHandlers . Add ( StreamingMessage . ContentOneofCase . InvocationCancel , ProcessInvocationCancelRequest ) ;
68
71
72
+ _requestHandlers . Add ( StreamingMessage . ContentOneofCase . FunctionsMetadataRequest , ProcessFunctionMetadataRequest ) ;
73
+
69
74
_requestHandlers . Add ( StreamingMessage . ContentOneofCase . FunctionEnvironmentReloadRequest , ProcessFunctionEnvironmentReloadRequest ) ;
70
75
}
71
76
@@ -95,6 +100,9 @@ internal async Task ProcessRequestLoop()
95
100
96
101
internal StreamingMessage ProcessWorkerInitRequest ( StreamingMessage request )
97
102
{
103
+ var stopwatch = new Stopwatch ( ) ;
104
+ stopwatch . Start ( ) ;
105
+
98
106
var workerInitRequest = request . WorkerInitRequest ;
99
107
Environment . SetEnvironmentVariable ( "AZUREPS_HOST_ENVIRONMENT" , $ "AzureFunctions/{ workerInitRequest . HostVersion } ") ;
100
108
Environment . SetEnvironmentVariable ( "POWERSHELL_DISTRIBUTION_CHANNEL" , $ "Azure-Functions:{ workerInitRequest . HostVersion } ") ;
@@ -117,6 +125,32 @@ internal StreamingMessage ProcessWorkerInitRequest(StreamingMessage request)
117
125
RemoteSessionNamedPipeServer . CreateCustomNamedPipeServer ( pipeName ) ;
118
126
}
119
127
128
+ // Previously, this half of the dependency management would happen just prior to the dependency download in the
129
+ // first function load request. Now that we have the FunctionAppDirectory in the WorkerInitRequest,
130
+ // we can do the setup of these variables in the function load request. We need these variables initialized
131
+ // for the FunctionMetadataRequest, should it be sent.
132
+ try
133
+ {
134
+ var rpcLogger = new RpcLogger ( _msgStream ) ;
135
+ rpcLogger . SetContext ( request . RequestId , null ) ;
136
+
137
+ _dependencyManager = new DependencyManager ( request . WorkerInitRequest . FunctionAppDirectory , logger : rpcLogger ) ;
138
+
139
+ _powershellPool . Initialize ( _firstPwshInstance ) ;
140
+
141
+ rpcLogger . Log ( isUserOnlyLog : false , LogLevel . Trace , string . Format ( PowerShellWorkerStrings . FirstFunctionLoadCompleted , stopwatch . ElapsedMilliseconds ) ) ;
142
+ }
143
+ catch ( Exception e )
144
+ {
145
+ // This is a terminating failure: we will need to return a failure response to
146
+ // all subsequent 'FunctionLoadRequest'. Cache the exception so we can reuse it in future calls.
147
+ _initTerminatingError = e ;
148
+
149
+ status . Status = StatusResult . Types . Status . Failure ;
150
+ status . Exception = e . ToRpcException ( ) ;
151
+ return response ;
152
+ }
153
+
120
154
return response ;
121
155
}
122
156
@@ -189,26 +223,20 @@ internal StreamingMessage ProcessFunctionLoadRequest(StreamingMessage request)
189
223
{
190
224
try
191
225
{
192
- _isFunctionAppInitialized = true ;
193
-
194
226
var rpcLogger = new RpcLogger ( _msgStream ) ;
195
227
rpcLogger . SetContext ( request . RequestId , null ) ;
196
228
197
- _dependencyManager = new DependencyManager ( request . FunctionLoadRequest . Metadata . Directory , logger : rpcLogger ) ;
198
- var managedDependenciesPath = _dependencyManager . Initialize ( request , rpcLogger ) ;
199
-
200
- SetupAppRootPathAndModulePath ( functionLoadRequest , managedDependenciesPath ) ;
229
+ _isFunctionAppInitialized = true ;
201
230
202
- _powershellPool . Initialize ( _firstPwshInstance ) ;
231
+ var managedDependenciesPath = _dependencyManager . Initialize ( request , rpcLogger ) ;
203
232
233
+ SetupAppRootPathAndModulePath ( request . FunctionLoadRequest , managedDependenciesPath ) ;
204
234
// Start the download asynchronously if needed.
205
235
_dependencyManager . StartDependencyInstallationIfNeeded ( request , _firstPwshInstance , rpcLogger ) ;
206
-
207
- rpcLogger . Log ( isUserOnlyLog : false , LogLevel . Trace , string . Format ( PowerShellWorkerStrings . FirstFunctionLoadCompleted , stopwatch . ElapsedMilliseconds ) ) ;
208
236
}
209
237
catch ( Exception e )
210
238
{
211
- // Failure that happens during this step is terminating and we will need to return a failure response to
239
+ // This is a terminating failure: we will need to return a failure response to
212
240
// all subsequent 'FunctionLoadRequest'. Cache the exception so we can reuse it in future calls.
213
241
_initTerminatingError = e ;
214
242
@@ -341,6 +369,18 @@ internal StreamingMessage ProcessInvocationCancelRequest(StreamingMessage reques
341
369
return null ;
342
370
}
343
371
372
+ private StreamingMessage ProcessFunctionMetadataRequest ( StreamingMessage request )
373
+ {
374
+ StreamingMessage response = NewStreamingMessageTemplate (
375
+ request . RequestId ,
376
+ StreamingMessage . ContentOneofCase . FunctionMetadataResponse ,
377
+ out StatusResult status ) ;
378
+
379
+ response . FunctionMetadataResponse . FunctionMetadataResults . AddRange ( WorkerIndexingHelper . IndexFunctions ( request . FunctionsMetadataRequest . FunctionAppDirectory ) ) ;
380
+
381
+ return response ;
382
+ }
383
+
344
384
internal StreamingMessage ProcessFunctionEnvironmentReloadRequest ( StreamingMessage request )
345
385
{
346
386
var stopwatch = new Stopwatch ( ) ;
@@ -394,6 +434,9 @@ private StreamingMessage NewStreamingMessageTemplate(string requestId, Streaming
394
434
case StreamingMessage . ContentOneofCase . FunctionEnvironmentReloadResponse :
395
435
response . FunctionEnvironmentReloadResponse = new FunctionEnvironmentReloadResponse ( ) { Result = status } ;
396
436
break ;
437
+ case StreamingMessage . ContentOneofCase . FunctionMetadataResponse :
438
+ response . FunctionMetadataResponse = new FunctionMetadataResponse ( ) { Result = status } ;
439
+ break ;
397
440
default :
398
441
throw new InvalidOperationException ( "Unreachable code." ) ;
399
442
}
0 commit comments