5
5
using System . Collections . Generic ;
6
6
using System . IO ;
7
7
using System . Linq ;
8
+ using System . Text . Json ;
8
9
using System . Text . RegularExpressions ;
9
10
using Microsoft . Azure . WebJobs . Script . Diagnostics ;
10
11
using Microsoft . Azure . WebJobs . Script . Workers . Profiles ;
11
12
using Microsoft . Extensions . Configuration ;
12
13
using Microsoft . Extensions . Logging ;
13
- using Newtonsoft . Json . Linq ;
14
14
15
15
namespace Microsoft . Azure . WebJobs . Script . Workers . Rpc
16
16
{
@@ -24,6 +24,10 @@ internal class RpcWorkerConfigFactory
24
24
private readonly IMetricsLogger _metricsLogger ;
25
25
private readonly string _workerRuntime ;
26
26
private readonly IEnvironment _environment ;
27
+ private readonly JsonSerializerOptions _jsonSerializerOptions = new ( )
28
+ {
29
+ PropertyNameCaseInsensitive = true
30
+ } ;
27
31
28
32
private Dictionary < string , RpcWorkerConfig > _workerDescriptionDictionary = new Dictionary < string , RpcWorkerConfig > ( ) ;
29
33
@@ -116,6 +120,18 @@ internal void AddProvider(string workerDir)
116
120
{
117
121
try
118
122
{
123
+ // After specialization, load worker config only for the specified runtime unless it's a multi-language app.
124
+ if ( ! string . IsNullOrWhiteSpace ( _workerRuntime ) && ! _environment . IsPlaceholderModeEnabled ( ) && ! _environment . IsMultiLanguageRuntimeEnvironment ( ) )
125
+ {
126
+ string workerRuntime = Path . GetFileName ( workerDir ) ;
127
+ // Only skip worker directories that don't match the current runtime.
128
+ // Do not skip non-worker directories like the function app payload directory
129
+ if ( ! workerRuntime . Equals ( _workerRuntime , StringComparison . OrdinalIgnoreCase ) && workerDir . StartsWith ( WorkersDirPath ) )
130
+ {
131
+ return ;
132
+ }
133
+ }
134
+
119
135
string workerConfigPath = Path . Combine ( workerDir , RpcWorkerConstants . WorkerConfigFileName ) ;
120
136
121
137
if ( ! File . Exists ( workerConfigPath ) )
@@ -126,15 +142,13 @@ internal void AddProvider(string workerDir)
126
142
127
143
_logger . LogDebug ( "Found worker config: {workerConfigPath}" , workerConfigPath ) ;
128
144
129
- // Parse worker config file
130
- string json = File . ReadAllText ( workerConfigPath ) ;
131
- JObject workerConfig = JObject . Parse ( json ) ;
132
- RpcWorkerDescription workerDescription = workerConfig . Property ( WorkerConstants . WorkerDescription ) . Value . ToObject < RpcWorkerDescription > ( ) ;
145
+ var workerConfig = GetWorkerConfigJsonElement ( workerConfigPath ) ;
146
+ var workerDescriptionElement = workerConfig . GetProperty ( WorkerConstants . WorkerDescription ) ;
147
+ var workerDescription = workerDescriptionElement . Deserialize < RpcWorkerDescription > ( _jsonSerializerOptions ) ;
133
148
workerDescription . WorkerDirectory = workerDir ;
134
149
135
- //Read the profiles from worker description and load the profile for which the conditions match
136
- JToken profiles = workerConfig . GetValue ( WorkerConstants . WorkerDescriptionProfiles ) ;
137
- if ( profiles != null )
150
+ // Read the profiles from worker description and load the profile for which the conditions match
151
+ if ( workerConfig . TryGetProperty ( WorkerConstants . WorkerDescriptionProfiles , out var profiles ) )
138
152
{
139
153
List < WorkerDescriptionProfile > workerDescriptionProfiles = ReadWorkerDescriptionProfiles ( profiles ) ;
140
154
if ( workerDescriptionProfiles . Count > 0 )
@@ -146,7 +160,7 @@ internal void AddProvider(string workerDir)
146
160
147
161
// Check if any app settings are provided for that language
148
162
var languageSection = _config . GetSection ( $ "{ RpcWorkerConstants . LanguageWorkersSectionName } :{ workerDescription . Language } ") ;
149
- workerDescription . Arguments = workerDescription . Arguments ?? new List < string > ( ) ;
163
+ workerDescription . Arguments ??= new List < string > ( ) ;
150
164
GetWorkerDescriptionFromAppSettings ( workerDescription , languageSection ) ;
151
165
AddArgumentsFromAppSettings ( workerDescription , languageSection ) ;
152
166
@@ -197,9 +211,24 @@ internal void AddProvider(string workerDir)
197
211
}
198
212
}
199
213
200
- private List < WorkerDescriptionProfile > ReadWorkerDescriptionProfiles ( JToken profilesJToken )
214
+ private static JsonElement GetWorkerConfigJsonElement ( string workerConfigPath )
201
215
{
202
- var profiles = profilesJToken . ToObject < IList < WorkerProfileDescriptor > > ( ) ;
216
+ ReadOnlySpan < byte > jsonSpan = File . ReadAllBytes ( workerConfigPath ) ;
217
+
218
+ if ( jsonSpan . StartsWith < byte > ( [ 0xEF , 0xBB , 0xBF ] ) )
219
+ {
220
+ jsonSpan = jsonSpan [ 3 ..] ; // Skip UTF-8 Byte Order Mark (BOM) if present at the beginning of the file.
221
+ }
222
+
223
+ var reader = new Utf8JsonReader ( jsonSpan , isFinalBlock : true , state : default ) ;
224
+ using var doc = JsonDocument . ParseValue ( ref reader ) ;
225
+
226
+ return doc . RootElement . Clone ( ) ;
227
+ }
228
+
229
+ private List < WorkerDescriptionProfile > ReadWorkerDescriptionProfiles ( JsonElement profilesElement )
230
+ {
231
+ var profiles = profilesElement . Deserialize < IList < WorkerProfileDescriptor > > ( _jsonSerializerOptions ) ;
203
232
204
233
if ( profiles == null || profiles . Count <= 0 )
205
234
{
@@ -237,11 +266,16 @@ private List<WorkerDescriptionProfile> ReadWorkerDescriptionProfiles(JToken prof
237
266
return descriptionProfiles ;
238
267
}
239
268
240
- internal WorkerProcessCountOptions GetWorkerProcessCount ( JObject workerConfig )
269
+ internal WorkerProcessCountOptions GetWorkerProcessCount ( JsonElement workerConfig )
241
270
{
242
- WorkerProcessCountOptions workerProcessCount = workerConfig . Property ( WorkerConstants . ProcessCount ) ? . Value . ToObject < WorkerProcessCountOptions > ( ) ;
271
+ WorkerProcessCountOptions workerProcessCount = null ;
272
+
273
+ if ( workerConfig . TryGetProperty ( WorkerConstants . ProcessCount , out var processCountElement ) )
274
+ {
275
+ workerProcessCount = processCountElement . Deserialize < WorkerProcessCountOptions > ( ) ;
276
+ }
243
277
244
- workerProcessCount = workerProcessCount ?? new WorkerProcessCountOptions ( ) ;
278
+ workerProcessCount ??= new WorkerProcessCountOptions ( ) ;
245
279
246
280
if ( workerProcessCount . SetProcessCountToNumberOfCpuCores )
247
281
{
0 commit comments