diff --git a/BaseSpace.SDK.Tests/BaseSpace.SDK.Tests.csproj b/BaseSpace.SDK.Tests/BaseSpace.SDK.Tests.csproj index a5ab4f4..fe85b21 100644 --- a/BaseSpace.SDK.Tests/BaseSpace.SDK.Tests.csproj +++ b/BaseSpace.SDK.Tests/BaseSpace.SDK.Tests.csproj @@ -42,6 +42,9 @@ $(SolutionDir)\packages\log4net.1.2.10\lib\2.0\log4net.dll + + ..\packages\Moq.4.2.1409.1722\lib\net40\Moq.dll + False $(SolutionDir)\packages\ServiceStack.Common.3.9.35\lib\net35\ServiceStack.Common.dll diff --git a/BaseSpace.SDK.Tests/JsonWebClientTests.cs b/BaseSpace.SDK.Tests/JsonWebClientTests.cs index 96c3dff..99fba71 100644 --- a/BaseSpace.SDK.Tests/JsonWebClientTests.cs +++ b/BaseSpace.SDK.Tests/JsonWebClientTests.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics; using Illumina.BaseSpace.SDK.Deserialization; +using Illumina.BaseSpace.SDK.ServiceModels; using Illumina.BaseSpace.SDK.Types; +using Moq; using Xunit; namespace Illumina.BaseSpace.SDK.Tests @@ -8,6 +11,61 @@ namespace Illumina.BaseSpace.SDK.Tests public class JsonWebClientTests { + [Fact] + public void RequestOptionsAreProperlyUsed() + { + var client = new BaseSpaceClient(new BaseSpaceClientSettings() + { + BaseSpaceApiUrl = "https://api.basespace.illumina.com", + Authentication = new OAuth2Authentication("xxxxx"), + TimeoutMin = .00001 + }); + + var sw = Stopwatch.StartNew(); + try + { + var ass = client.GetAppSession(new GetAppSessionRequest("xxxx"), new RequestOptions(6,.1)); + } + catch (Exception) + { + + } + sw.Stop(); + + Assert.InRange(sw.ElapsedMilliseconds,0,10*1000); + + } + + + [Fact(Skip = "disabled since it needs token and session")] + public void CanRespawnClientAtEachRetry() + { + var setting = new BaseSpaceClientSettings() + { + BaseSpaceApiUrl = "https://api.cloud-test.illumina.com", + Authentication = new OAuth2Authentication("xxxxx"), + TimeoutMin = .0000000001 + }; + + var client = new Mock(setting, null); + int retry = 0; + client.Setup(c => c.RespawnClient()).Callback(() => + { + // this should occur only once and because of the ridiculous timeout + Assert.Equal(1, ++retry); + + // respawn the client with a normal timeout + // should be proof that the newly created client + // is used on second retry + client.Object._clientFactoryMethod(); + client.Object.client.Timeout = TimeSpan.FromMinutes(1); + }); + + var ass = client.Object.Send(new GetAppSessionRequest("xxxxx"), new RequestOptions(6, .1)); + } + + + [Fact] public void CanDeserializeARunCompactReference() { diff --git a/BaseSpace.SDK.Tests/packages.config b/BaseSpace.SDK.Tests/packages.config index f3b4699..7041800 100644 --- a/BaseSpace.SDK.Tests/packages.config +++ b/BaseSpace.SDK.Tests/packages.config @@ -2,6 +2,7 @@ + diff --git a/BaseSpace.SDK/Infrastructure/BaseSpaceClientSettings.cs b/BaseSpace.SDK/Infrastructure/BaseSpaceClientSettings.cs index 9489b5e..c5a23e2 100644 --- a/BaseSpace.SDK/Infrastructure/BaseSpaceClientSettings.cs +++ b/BaseSpace.SDK/Infrastructure/BaseSpaceClientSettings.cs @@ -1,8 +1,9 @@ namespace Illumina.BaseSpace.SDK { public class BaseSpaceClientSettings : IClientSettings - { - public const uint DEFAULT_RETRY_ATTEMPTS = 6; + { + public const uint DEFAULT_RETRY_ATTEMPTS = 6; + public const uint DEFAULT_RETRY_POWER_BASE = 5; public const string DEFAULT_WEBSITE = "https://basespace.illumina.com"; @@ -48,6 +49,6 @@ public BaseSpaceClientSettings() public IAuthentication Authentication { get; set; } - public int TimeoutMin { get; set; } + public double TimeoutMin { get; set; } } } diff --git a/BaseSpace.SDK/Infrastructure/JsonWebClient.cs b/BaseSpace.SDK/Infrastructure/JsonWebClient.cs index 440c5f4..e5594db 100644 --- a/BaseSpace.SDK/Infrastructure/JsonWebClient.cs +++ b/BaseSpace.SDK/Infrastructure/JsonWebClient.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net; +using System.Runtime.Remoting.Messaging; using System.Web.Util; using Common.Logging; using Illumina.BaseSpace.SDK.Deserialization; @@ -15,16 +16,27 @@ namespace Illumina.BaseSpace.SDK { public class JsonWebClient : IWebClient { - private readonly JsonServiceClient client; - private readonly JsonServiceClient clientBilling; + internal JsonServiceClient client; + private JsonServiceClient clientBilling; - private readonly ILog logger; + private ILog logger; - private readonly IClientSettings settings; + private IClientSettings settings; + + public virtual void RespawnClient() + { + if (_clientFactoryMethod != null) + _clientFactoryMethod(); + } + + + internal readonly Action _clientFactoryMethod; public JsonWebClient(IClientSettings settings, IRequestOptions defaultOptions = null) { + _clientFactoryMethod = () => + { if (settings == null) { throw new ArgumentNullException("settings"); @@ -53,6 +65,9 @@ public JsonWebClient(IClientSettings settings, IRequestOptions defaultOptions = clientBilling = new JsonServiceClient(settings.BaseSpaceBillingApiUrl); clientBilling.LocalHttpWebRequestFilter += WebRequestFilter; + }; + + _clientFactoryMethod(); } static JsonWebClient() @@ -108,10 +123,13 @@ public TReturn Send(AbstractRequest request, IRequestOptions o TReturn result = null; options = options ?? DefaultRequestOptions; - var clientForRequest = PickClientForApiName(request.GetApiName()); - RetryLogic.DoWithRetry(options.RetryAttempts, request.GetName(), - () => result = request.GetSendFunc(clientForRequest)(), logger); + RetryLogic.DoWithRetry(options.RetryAttempts, request.GetName(), () => result = request.GetSendFunc(PickClientForApiName(request.GetApiName()))(), logger, + retryIntervalBaseSecs:options.RetryPowerBase,retryHandler: (exc) => + { + RespawnClient(); + return RetryLogic.GenericRetryHandler(exc); + }); return result; } catch (WebServiceException webx) diff --git a/BaseSpace.SDK/Interfaces/IClientSettings.cs b/BaseSpace.SDK/Interfaces/IClientSettings.cs index 734a168..a349bc8 100644 --- a/BaseSpace.SDK/Interfaces/IClientSettings.cs +++ b/BaseSpace.SDK/Interfaces/IClientSettings.cs @@ -19,6 +19,6 @@ public interface IClientSettings IAuthentication Authentication { get; } - int TimeoutMin { get; } + double TimeoutMin { get; } } } diff --git a/BaseSpace.SDK/Interfaces/IRequestOptions.cs b/BaseSpace.SDK/Interfaces/IRequestOptions.cs index 772c20f..749aea8 100644 --- a/BaseSpace.SDK/Interfaces/IRequestOptions.cs +++ b/BaseSpace.SDK/Interfaces/IRequestOptions.cs @@ -1,8 +1,13 @@ namespace Illumina.BaseSpace.SDK { - public interface IRequestOptions + public interface IRetryOptions + { + uint RetryAttempts { get; } + double RetryPowerBase { get; } + } + + public interface IRequestOptions: IRetryOptions { - uint RetryAttempts { get; } } } diff --git a/BaseSpace.SDK/Properties/AssemblyInfo.cs b/BaseSpace.SDK/Properties/AssemblyInfo.cs index 16cc3b6..7ba1d01 100644 --- a/BaseSpace.SDK/Properties/AssemblyInfo.cs +++ b/BaseSpace.SDK/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ [assembly: AssemblyVersion("1.0.0.9")] [assembly: AssemblyFileVersion("1.0.0.9")] //[assembly: InternalsVisibleTo("Illumina.BaseSpace.SDK.Private")] //Sujit: had to comment this out to allow strong sigining TV for BaseSpaceDownloader -//[assembly: InternalsVisibleTo("Illumina.BaseSpace.SDK.Tests")] //Sujit: had to comment this out to allow strong sigining TV for BaseSpaceDownloader +[assembly: InternalsVisibleTo("Illumina.BaseSpace.SDK.Tests")] //Sujit: had to comment this out to allow strong sigining TV for BaseSpaceDownloader //[assembly: InternalsVisibleTo("Illumina.BaseSpace.SDK.Private.Tests")]//Sujit: had to comment this out to allow strong sigining TV for BaseSpaceDownloader diff --git a/BaseSpace.SDK/Types/RequestOptions.cs b/BaseSpace.SDK/Types/RequestOptions.cs index e63be97..c92d5a0 100644 --- a/BaseSpace.SDK/Types/RequestOptions.cs +++ b/BaseSpace.SDK/Types/RequestOptions.cs @@ -2,11 +2,14 @@ { public class RequestOptions : IRequestOptions { - public RequestOptions(uint retryAttempts = BaseSpaceClientSettings.DEFAULT_RETRY_ATTEMPTS) + public RequestOptions(uint retryAttempts = BaseSpaceClientSettings.DEFAULT_RETRY_ATTEMPTS, + double powerbase = BaseSpaceClientSettings.DEFAULT_RETRY_POWER_BASE) { RetryAttempts = retryAttempts; + RetryPowerBase = powerbase; } public uint RetryAttempts { get; set; } - } + public double RetryPowerBase { get; set; } + } }