2323using Newtonsoft . Json ;
2424using Microsoft . Win32 ;
2525using Microsoft . VisualStudio . Services . Agent . Listener . Telemetry ;
26+ using Microsoft . TeamFoundation . Test . WebApi ;
2627
2728namespace Microsoft . VisualStudio . Services . Agent . Listener . Configuration
2829{
@@ -45,6 +46,8 @@ public sealed class ConfigurationManager : AgentService, IConfigurationManager
4546
4647 private const string VsTelemetryRegPath = @"SOFTWARE\Microsoft\VisualStudio\Telemetry\PersistentPropertyBag\c57a9efce9b74de382d905a89852db71" ;
4748 private const string VsTelemetryRegKey = "IsPipelineAgent" ;
49+ private const int _maxRetries = 3 ;
50+ private const int _delaySeconds = 2 ;
4851
4952 public override void Initialize ( IHostContext hostContext )
5053 {
@@ -252,18 +255,15 @@ public async Task ConfigureAsync(CommandSettings command)
252255 {
253256 // Update existing agent with new PublicKey, agent version and SystemCapabilities.
254257 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 )
257263 {
258- agent = await agentProvider . UpdateAgentAsync ( agentSettings , agent , command ) ;
259264 _term . WriteLine ( StringUtil . Loc ( "AgentReplaced" ) ) ;
260265 break ;
261266 }
262- catch ( Exception e ) when ( ! command . Unattended ( ) )
263- {
264- _term . WriteError ( e ) ;
265- _term . WriteError ( StringUtil . Loc ( "FailedToReplaceAgent" ) ) ;
266- }
267267 }
268268 else if ( command . Unattended ( ) )
269269 {
@@ -455,6 +455,58 @@ public async Task ConfigureAsync(CommandSettings command)
455455 }
456456 }
457457
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+
458510 public async Task UnconfigureAsync ( CommandSettings command )
459511 {
460512 ArgUtil . NotNull ( command , nameof ( command ) ) ;
@@ -695,19 +747,18 @@ public async Task ReAuthAsync(CommandSettings command)
695747 }
696748 else
697749 {
698- try
750+ agent . Authorization = new TaskAgentAuthorization
699751 {
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 )
708759 {
709- _term . WriteError ( e ) ;
710- _term . WriteError ( StringUtil . Loc ( "FailedToReplaceAgent" ) ) ;
760+ _term . WriteLine ( StringUtil . Loc ( "AgentReplaced" ) ) ;
761+ break ;
711762 }
712763 }
713764
@@ -838,7 +889,6 @@ private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey,
838889 {
839890 agent . SystemCapabilities [ capability . Key ] = capability . Value ?? string . Empty ;
840891 }
841-
842892 return agent ;
843893 }
844894
0 commit comments