@@ -46,9 +46,10 @@ public InstanceManager(IOptionsFactory<ScriptApplicationHostOptions> optionsFact
46
46
_optionsFactory = optionsFactory ?? throw new ArgumentNullException ( nameof ( optionsFactory ) ) ;
47
47
}
48
48
49
- public async Task < string > SpecializeMSISidecar ( HostAssignmentContext context , bool isWarmup )
49
+ public async Task < string > SpecializeMSISidecar ( HostAssignmentContext context )
50
50
{
51
- if ( isWarmup )
51
+ // No cold start optimization needed for side car scenarios
52
+ if ( context . IsWarmupRequest )
52
53
{
53
54
return null ;
54
55
}
@@ -89,16 +90,19 @@ public async Task<string> SpecializeMSISidecar(HostAssignmentContext context, bo
89
90
return null ;
90
91
}
91
92
92
- public bool StartAssignment ( HostAssignmentContext context , bool isWarmup )
93
+ public bool StartAssignment ( HostAssignmentContext context )
93
94
{
94
95
if ( ! _webHostEnvironment . InStandbyMode )
95
96
{
96
97
_logger . LogError ( "Assign called while host is not in placeholder mode" ) ;
97
98
return false ;
98
99
}
99
100
100
- if ( isWarmup )
101
+ if ( context . IsWarmupRequest )
101
102
{
103
+ // Based on profiling download code jit-ing holds up cold start.
104
+ // Pre-jit to avoid paying the cost later.
105
+ Task . Run ( async ( ) => await Download ( context . GetRunFromPkgContext ( ) ) ) ;
102
106
return true ;
103
107
}
104
108
else if ( _assignmentContext == null )
@@ -134,16 +138,11 @@ public bool StartAssignment(HostAssignmentContext context, bool isWarmup)
134
138
}
135
139
}
136
140
137
- public async Task < string > ValidateContext ( HostAssignmentContext assignmentContext , bool isWarmup )
141
+ public async Task < string > ValidateContext ( HostAssignmentContext assignmentContext )
138
142
{
139
- if ( isWarmup )
140
- {
141
- return null ;
142
- }
143
-
144
- _logger . LogInformation ( $ "Validating host assignment context (SiteId: { assignmentContext . SiteId } , SiteName: '{ assignmentContext . SiteName } ')") ;
143
+ _logger . LogInformation ( $ "Validating host assignment context (SiteId: { assignmentContext . SiteId } , SiteName: '{ assignmentContext . SiteName } '. IsWarmup: '{ assignmentContext . IsWarmupRequest } ')") ;
145
144
RunFromPackageContext pkgContext = assignmentContext . GetRunFromPkgContext ( ) ;
146
- _logger . LogInformation ( $ "Will be using { pkgContext . EnvironmentVariableName } app setting as zip url") ;
145
+ _logger . LogInformation ( $ "Will be using { pkgContext . EnvironmentVariableName } app setting as zip url. IsWarmup: ' { assignmentContext . IsWarmupRequest } ') ") ;
147
146
148
147
if ( pkgContext . IsScmRunFromPackage ( ) )
149
148
{
@@ -154,7 +153,7 @@ public async Task<string> ValidateContext(HostAssignmentContext assignmentContex
154
153
{
155
154
// In AppService, ZipUrl == 1 means the package is hosted in azure files.
156
155
// Otherwise we expect zipUrl to be a blobUri to a zip or a squashfs image
157
- ( var error , var contentLength ) = await ValidateBlobPackageContext ( pkgContext . Url ) ;
156
+ ( var error , var contentLength ) = await ValidateBlobPackageContext ( pkgContext ) ;
158
157
if ( string . IsNullOrEmpty ( error ) )
159
158
{
160
159
assignmentContext . PackageContentLength = contentLength ;
@@ -172,8 +171,12 @@ public async Task<string> ValidateContext(HostAssignmentContext assignmentContex
172
171
}
173
172
}
174
173
175
- private async Task < ( string , long ? ) > ValidateBlobPackageContext ( string blobUri )
174
+ private async Task < ( string , long ? ) > ValidateBlobPackageContext ( RunFromPackageContext context )
176
175
{
176
+ string blobUri = context . Url ;
177
+ string eventName = context . IsWarmUpRequest
178
+ ? MetricEventNames . LinuxContainerSpecializationZipHeadWarmup
179
+ : MetricEventNames . LinuxContainerSpecializationZipHead ;
177
180
string error = null ;
178
181
HttpResponseMessage response = null ;
179
182
long ? contentLength = null ;
@@ -186,7 +189,7 @@ await Utility.InvokeWithRetriesAsync(async () =>
186
189
{
187
190
try
188
191
{
189
- using ( _metricsLogger . LatencyEvent ( MetricEventNames . LinuxContainerSpecializationZipHead ) )
192
+ using ( _metricsLogger . LatencyEvent ( eventName ) )
190
193
{
191
194
var request = new HttpRequestMessage ( HttpMethod . Head , blobUri ) ;
192
195
response = await _client . SendAsync ( request ) ;
@@ -199,7 +202,7 @@ await Utility.InvokeWithRetriesAsync(async () =>
199
202
}
200
203
catch ( Exception e )
201
204
{
202
- _logger . LogError ( e , $ "{ MetricEventNames . LinuxContainerSpecializationZipHead } failed") ;
205
+ _logger . LogError ( e , $ "{ eventName } failed") ;
203
206
throw ;
204
207
}
205
208
} , maxRetries : 2 , retryInterval : TimeSpan . FromSeconds ( 0.3 ) ) ; // Keep this less than ~1s total
@@ -208,7 +211,7 @@ await Utility.InvokeWithRetriesAsync(async () =>
208
211
catch ( Exception e )
209
212
{
210
213
error = $ "Invalid zip url specified (StatusCode: { response ? . StatusCode } )";
211
- _logger . LogError ( e , "ValidateContext failed" ) ;
214
+ _logger . LogError ( e , $ "ValidateContext failed. IsWarmupRequest = { context . IsWarmUpRequest } ") ;
212
215
}
213
216
214
217
return ( error , contentLength ) ;
@@ -372,25 +375,28 @@ private async Task<string> Download(RunFromPackageContext pkgContext)
372
375
if ( pkgContext . PackageContentLength != null && pkgContext . PackageContentLength > 100 * 1024 * 1024 )
373
376
{
374
377
_logger . LogInformation ( $ "Downloading zip contents from '{ cleanedUrl } ' using aria2c'") ;
375
- AriaDownload ( tmpPath , fileName , zipUri ) ;
378
+ AriaDownload ( tmpPath , fileName , zipUri , pkgContext . IsWarmUpRequest ) ;
376
379
}
377
380
else
378
381
{
379
382
_logger . LogInformation ( $ "Downloading zip contents from '{ cleanedUrl } ' using httpclient'") ;
380
- await HttpClientDownload ( filePath , zipUri ) ;
383
+ await HttpClientDownload ( filePath , zipUri , pkgContext . IsWarmUpRequest ) ;
381
384
}
382
385
383
386
return filePath ;
384
387
}
385
388
386
- private async Task HttpClientDownload ( string filePath , Uri zipUri )
389
+ private async Task HttpClientDownload ( string filePath , Uri zipUri , bool isWarmupRequest )
387
390
{
388
391
HttpResponseMessage response = null ;
389
392
await Utility . InvokeWithRetriesAsync ( async ( ) =>
390
393
{
391
394
try
392
395
{
393
- using ( _metricsLogger . LatencyEvent ( MetricEventNames . LinuxContainerSpecializationZipDownload ) )
396
+ var downloadMetricName = isWarmupRequest
397
+ ? MetricEventNames . LinuxContainerSpecializationZipDownloadWarmup
398
+ : MetricEventNames . LinuxContainerSpecializationZipDownload ;
399
+ using ( _metricsLogger . LatencyEvent ( downloadMetricName ) )
394
400
{
395
401
var request = new HttpRequestMessage ( HttpMethod . Get , zipUri ) ;
396
402
response = await _client . SendAsync ( request , HttpCompletionOption . ResponseHeadersRead ) ;
@@ -403,31 +409,36 @@ await Utility.InvokeWithRetriesAsync(async () =>
403
409
_logger . LogError ( e , error ) ;
404
410
throw ;
405
411
}
406
- _logger . LogInformation ( $ "{ response . Content . Headers . ContentLength } bytes downloaded") ;
412
+ _logger . LogInformation ( $ "{ response . Content . Headers . ContentLength } bytes downloaded. IsWarmupRequest = { isWarmupRequest } ") ;
407
413
} , 2 , TimeSpan . FromSeconds ( 0.5 ) ) ;
408
414
409
- using ( _metricsLogger . LatencyEvent ( MetricEventNames . LinuxContainerSpecializationZipWrite ) )
415
+ using ( _metricsLogger . LatencyEvent ( isWarmupRequest ? MetricEventNames . LinuxContainerSpecializationZipWriteWarmup : MetricEventNames . LinuxContainerSpecializationZipWrite ) )
410
416
{
411
417
using ( var content = await response . Content . ReadAsStreamAsync ( ) )
412
418
using ( var stream = new FileStream ( filePath , FileMode . Create , FileAccess . Write , FileShare . None , bufferSize : 4096 , useAsync : true ) )
413
419
{
414
420
await content . CopyToAsync ( stream ) ;
415
421
}
416
- _logger . LogInformation ( $ "{ response . Content . Headers . ContentLength } bytes written") ;
422
+ _logger . LogInformation ( $ "{ response . Content . Headers . ContentLength } bytes written. IsWarmupRequest = { isWarmupRequest } ") ;
417
423
}
418
424
}
419
425
420
- private void AriaDownload ( string directory , string fileName , Uri zipUri )
426
+ private void AriaDownload ( string directory , string fileName , Uri zipUri , bool isWarmupRequest )
421
427
{
422
- ( string stdout , string stderr , int exitCode ) = RunBashCommand ( $ "aria2c --allow-overwrite -x12 -d { directory } -o { fileName } '{ zipUri } '", MetricEventNames . LinuxContainerSpecializationZipDownload ) ;
428
+ var metricName = isWarmupRequest
429
+ ? MetricEventNames . LinuxContainerSpecializationZipDownloadWarmup
430
+ : MetricEventNames . LinuxContainerSpecializationZipDownload ;
431
+ ( string stdout , string stderr , int exitCode ) = RunBashCommand (
432
+ $ "aria2c --allow-overwrite -x12 -d { directory } -o { fileName } '{ zipUri } '",
433
+ metricName ) ;
423
434
if ( exitCode != 0 )
424
435
{
425
436
var msg = $ "Error downloading package. stdout: { stdout } , stderr: { stderr } , exitCode: { exitCode } ";
426
437
_logger . LogError ( msg ) ;
427
438
throw new InvalidOperationException ( msg ) ;
428
439
}
429
440
var fileInfo = FileUtility . FileInfoFromFileName ( Path . Combine ( directory , fileName ) ) ;
430
- _logger . LogInformation ( $ "{ fileInfo . Length } bytes downloaded") ;
441
+ _logger . LogInformation ( $ "{ fileInfo . Length } bytes downloaded. IsWarmupRequest = { isWarmupRequest } ") ;
431
442
}
432
443
433
444
private async Task UnpackPackage ( string filePath , string scriptPath , RunFromPackageContext pkgContext )
0 commit comments