23
23
using Newtonsoft . Json ;
24
24
using Microsoft . Win32 ;
25
25
using Microsoft . VisualStudio . Services . Agent . Listener . Telemetry ;
26
+ using Microsoft . TeamFoundation . Test . WebApi ;
26
27
27
28
namespace Microsoft . VisualStudio . Services . Agent . Listener . Configuration
28
29
{
@@ -45,6 +46,8 @@ public sealed class ConfigurationManager : AgentService, IConfigurationManager
45
46
46
47
private const string VsTelemetryRegPath = @"SOFTWARE\Microsoft\VisualStudio\Telemetry\PersistentPropertyBag\c57a9efce9b74de382d905a89852db71" ;
47
48
private const string VsTelemetryRegKey = "IsPipelineAgent" ;
49
+ private const int _maxRetries = 3 ;
50
+ private const int _delaySeconds = 2 ;
48
51
49
52
public override void Initialize ( IHostContext hostContext )
50
53
{
@@ -252,18 +255,15 @@ public async Task ConfigureAsync(CommandSettings command)
252
255
{
253
256
// Update existing agent with new PublicKey, agent version and SystemCapabilities.
254
257
agent = UpdateExistingAgent ( agent , publicKey , systemCapabilities ) ;
255
-
256
- try
258
+ agent = await UpdateAgentWithRetryAsync < TaskAgent > (
259
+ ( ) => agentProvider . UpdateAgentAsync ( agentSettings , agent , command ) ,
260
+ command
261
+ ) ;
262
+ if ( agent != null )
257
263
{
258
- agent = await agentProvider . UpdateAgentAsync ( agentSettings , agent , command ) ;
259
264
_term . WriteLine ( StringUtil . Loc ( "AgentReplaced" ) ) ;
260
265
break ;
261
266
}
262
- catch ( Exception e ) when ( ! command . Unattended ( ) )
263
- {
264
- _term . WriteError ( e ) ;
265
- _term . WriteError ( StringUtil . Loc ( "FailedToReplaceAgent" ) ) ;
266
- }
267
267
}
268
268
else if ( command . Unattended ( ) )
269
269
{
@@ -455,6 +455,58 @@ public async Task ConfigureAsync(CommandSettings command)
455
455
}
456
456
}
457
457
458
+ private async Task < T > UpdateAgentWithRetryAsync < T > (
459
+ Func < Task < T > > operation ,
460
+ CommandSettings command )
461
+ {
462
+ int attempt = 0 ;
463
+ while ( true )
464
+ {
465
+ try
466
+ {
467
+ return await operation ( ) ;
468
+ }
469
+ catch ( Exception e ) when (
470
+ e is TimeoutException ||
471
+ e is TaskCanceledException ||
472
+ ( e is OperationCanceledException && ! ( e is TaskCanceledException ) )
473
+ )
474
+ {
475
+ attempt ++ ;
476
+ if ( command . Unattended ( ) )
477
+ {
478
+ if ( attempt >= _maxRetries )
479
+ {
480
+ _term . WriteError ( e ) ;
481
+ _term . WriteError ( StringUtil . Loc ( "FailedToReplaceAgent" ) ) ;
482
+ Trace . Error ( $ "{ operation . Method . Name } failed after maximum retries. Exception: { e } ") ;
483
+ throw new InvalidOperationException ( StringUtil . Loc ( "FailedToReplaceAgent" ) , e ) ;
484
+ }
485
+ else
486
+ {
487
+ Trace . Info ( $ "Retrying operation, Attempt: '{ attempt } '.") ;
488
+ int backoff = _delaySeconds * ( int ) Math . Pow ( 2 , attempt - 1 ) ;
489
+ _term . WriteLine ( StringUtil . Loc ( "RetryingReplaceAgent" , attempt , _maxRetries , backoff ) ) ;
490
+ await Task . Delay ( TimeSpan . FromSeconds ( backoff ) ) ;
491
+ }
492
+ }
493
+ else
494
+ {
495
+ _term . WriteError ( e ) ;
496
+ _term . WriteError ( StringUtil . Loc ( "FailedToReplaceAgent" ) ) ;
497
+ break ;
498
+ }
499
+ }
500
+ catch ( Exception e )
501
+ {
502
+ _term . WriteError ( e ) ;
503
+ _term . WriteError ( StringUtil . Loc ( "FailedToReplaceAgent" ) ) ;
504
+ break ;
505
+ }
506
+ }
507
+ return default ( T ) ;
508
+ }
509
+
458
510
public async Task UnconfigureAsync ( CommandSettings command )
459
511
{
460
512
ArgUtil . NotNull ( command , nameof ( command ) ) ;
@@ -695,19 +747,18 @@ public async Task ReAuthAsync(CommandSettings command)
695
747
}
696
748
else
697
749
{
698
- try
750
+ agent . Authorization = new TaskAgentAuthorization
699
751
{
700
- agent . Authorization = new TaskAgentAuthorization
701
- {
702
- PublicKey = new TaskAgentPublicKey ( publicKey . Exponent , publicKey . Modulus ) ,
703
- } ;
704
- agent = await agentProvider . UpdateAgentAsync ( agentSettings , agent , command ) ;
705
- _term . WriteLine ( StringUtil . Loc ( "AgentReplaced" ) ) ;
706
- }
707
- catch ( Exception e ) when ( ! command . Unattended ( ) )
752
+ PublicKey = new TaskAgentPublicKey ( publicKey . Exponent , publicKey . Modulus ) ,
753
+ } ;
754
+ agent = await UpdateAgentWithRetryAsync < TaskAgent > (
755
+ ( ) => agentProvider . UpdateAgentAsync ( agentSettings , agent , command ) ,
756
+ command
757
+ ) ;
758
+ if ( agent != null )
708
759
{
709
- _term . WriteError ( e ) ;
710
- _term . WriteError ( StringUtil . Loc ( "FailedToReplaceAgent" ) ) ;
760
+ _term . WriteLine ( StringUtil . Loc ( "AgentReplaced" ) ) ;
761
+ break ;
711
762
}
712
763
}
713
764
@@ -838,7 +889,6 @@ private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey,
838
889
{
839
890
agent . SystemCapabilities [ capability . Key ] = capability . Value ?? string . Empty ;
840
891
}
841
-
842
892
return agent ;
843
893
}
844
894
0 commit comments