1818
1919namespace Microsoft . Azure . Functions . PowerShellWorker
2020{
21+ using Microsoft . Azure . Functions . PowerShellWorker . WorkerIndexing ;
22+ using Microsoft . PowerShell ;
2123 using System . Diagnostics ;
24+ using System . Text . Json ;
2225 using LogLevel = Microsoft . Azure . WebJobs . Script . Grpc . Messages . RpcLog . Types . Level ;
2326
2427 internal class RequestProcessor
@@ -66,6 +69,8 @@ internal RequestProcessor(MessagingStream msgStream, System.Management.Automatio
6669 // If an invocation is cancelled, host will receive an invocation response with status cancelled.
6770 _requestHandlers . Add ( StreamingMessage . ContentOneofCase . InvocationCancel , ProcessInvocationCancelRequest ) ;
6871
72+ _requestHandlers . Add ( StreamingMessage . ContentOneofCase . FunctionsMetadataRequest , ProcessFunctionMetadataRequest ) ;
73+
6974 _requestHandlers . Add ( StreamingMessage . ContentOneofCase . FunctionEnvironmentReloadRequest , ProcessFunctionEnvironmentReloadRequest ) ;
7075 }
7176
@@ -95,6 +100,9 @@ internal async Task ProcessRequestLoop()
95100
96101 internal StreamingMessage ProcessWorkerInitRequest ( StreamingMessage request )
97102 {
103+ var stopwatch = new Stopwatch ( ) ;
104+ stopwatch . Start ( ) ;
105+
98106 var workerInitRequest = request . WorkerInitRequest ;
99107 Environment . SetEnvironmentVariable ( "AZUREPS_HOST_ENVIRONMENT" , $ "AzureFunctions/{ workerInitRequest . HostVersion } ") ;
100108 Environment . SetEnvironmentVariable ( "POWERSHELL_DISTRIBUTION_CHANNEL" , $ "Azure-Functions:{ workerInitRequest . HostVersion } ") ;
@@ -117,6 +125,32 @@ internal StreamingMessage ProcessWorkerInitRequest(StreamingMessage request)
117125 RemoteSessionNamedPipeServer . CreateCustomNamedPipeServer ( pipeName ) ;
118126 }
119127
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+
120154 return response ;
121155 }
122156
@@ -189,26 +223,20 @@ internal StreamingMessage ProcessFunctionLoadRequest(StreamingMessage request)
189223 {
190224 try
191225 {
192- _isFunctionAppInitialized = true ;
193-
194226 var rpcLogger = new RpcLogger ( _msgStream ) ;
195227 rpcLogger . SetContext ( request . RequestId , null ) ;
196228
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 ;
201230
202- _powershellPool . Initialize ( _firstPwshInstance ) ;
231+ var managedDependenciesPath = _dependencyManager . Initialize ( request , rpcLogger ) ;
203232
233+ SetupAppRootPathAndModulePath ( request . FunctionLoadRequest , managedDependenciesPath ) ;
204234 // Start the download asynchronously if needed.
205235 _dependencyManager . StartDependencyInstallationIfNeeded ( request , _firstPwshInstance , rpcLogger ) ;
206-
207- rpcLogger . Log ( isUserOnlyLog : false , LogLevel . Trace , string . Format ( PowerShellWorkerStrings . FirstFunctionLoadCompleted , stopwatch . ElapsedMilliseconds ) ) ;
208236 }
209237 catch ( Exception e )
210238 {
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
212240 // all subsequent 'FunctionLoadRequest'. Cache the exception so we can reuse it in future calls.
213241 _initTerminatingError = e ;
214242
@@ -341,6 +369,18 @@ internal StreamingMessage ProcessInvocationCancelRequest(StreamingMessage reques
341369 return null ;
342370 }
343371
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+
344384 internal StreamingMessage ProcessFunctionEnvironmentReloadRequest ( StreamingMessage request )
345385 {
346386 var stopwatch = new Stopwatch ( ) ;
@@ -394,6 +434,9 @@ private StreamingMessage NewStreamingMessageTemplate(string requestId, Streaming
394434 case StreamingMessage . ContentOneofCase . FunctionEnvironmentReloadResponse :
395435 response . FunctionEnvironmentReloadResponse = new FunctionEnvironmentReloadResponse ( ) { Result = status } ;
396436 break ;
437+ case StreamingMessage . ContentOneofCase . FunctionMetadataResponse :
438+ response . FunctionMetadataResponse = new FunctionMetadataResponse ( ) { Result = status } ;
439+ break ;
397440 default :
398441 throw new InvalidOperationException ( "Unreachable code." ) ;
399442 }
0 commit comments