Refresh state container consisting of credentials and the date of the their expiration
        private void RenewCredentials(object unused)
        {
            // By default, the refreshRate will continue to be
            // _refreshRate, but if FetchCredentials() returns an expired credential,
            // the refresh rate will be adjusted
            var refreshRate = _refreshRate;

            try
            {
                // if FetchCredentials() call were to fail, _lastRetrievedCredentials
                // would remain unchanged and would continue to be returned in GetCredentials()
                _lastRetrievedCredentials = FetchCredentials();

                if (_lastRetrievedCredentials.IsExpiredWithin(TimeSpan.Zero))
                {
                    // relax the refresh rate to at least 5 minutes
                    refreshRate = TimeSpan.FromMinutes(new Random().Next(5, 16));
                }
            }
            catch (OperationCanceledException e)
            {
                _logger.Error(e, "RenewCredentials task canceled");
            }
            catch (Exception e)
            {
                // we want to suppress any exceptions from this timer task.
                _logger.Error(e, FailedToGetCredentialsMessage);
            }
            finally
            {
                // re-invoke this task once after time specified by refreshRate set at beginning of this method
                _credentialsRetrieverTimer.Change(refreshRate, _neverTimespan);
            }
        }
        /// <summary>
        /// Returns a copy of the most recent instance profile credentials.
        /// </summary>
        public override ImmutableCredentials GetCredentials()
        {
            CheckIsIMDSEnabled();
            ImmutableCredentials credentials = null;

            // Try to acquire read lock. The thread would be blocked if another thread has write lock.
            if (_credentialsLock.TryEnterReadLock(_credentialsLockTimeout))
            {
                try
                {
                    if (null != _lastRetrievedCredentials)
                    {
                        // if credentials are expired, we'll still return them, but log a message about
                        // them being expired.
                        if (_lastRetrievedCredentials.IsExpiredWithin(TimeSpan.Zero))
                        {
                            _logger.InfoFormat(_usingExpiredCredentialsFromIMDS);
                        }

                        return(_lastRetrievedCredentials?.Credentials.Copy());
                    }
                }
                finally
                {
                    _credentialsLock.ExitReadLock();
                }
            }

            // If there's no credentials cached, hit IMDS directly. Try to acquire write lock.
            if (_credentialsLock.TryEnterWriteLock(_credentialsLockTimeout))
            {
                try
                {
                    // Check for last retrieved credentials again in case other thread might have already fetched it.
                    if (null == _lastRetrievedCredentials)
                    {
                        _lastRetrievedCredentials = FetchCredentials();
                    }

                    // if credentials are expired, we'll still return them, but log a message about
                    // them being expired.
                    if (_lastRetrievedCredentials.IsExpiredWithin(TimeSpan.Zero))
                    {
                        _logger.InfoFormat(_usingExpiredCredentialsFromIMDS);
                    }

                    credentials = _lastRetrievedCredentials.Credentials?.Copy();
                }
                finally
                {
                    _credentialsLock.ExitWriteLock();
                }
            }

            if (credentials == null)
            {
                throw new AmazonServiceException(FailedToGetCredentialsMessage);
            }

            return(credentials);
        }