From 31c3d4c9d63e5f3acfcb3eab9e24de3a47bb465f Mon Sep 17 00:00:00 2001 From: gvessere Date: Wed, 19 Nov 2014 10:36:44 -0800 Subject: [PATCH 1/3] re-spawn client on retries --- BaseSpace.SDK/Infrastructure/JsonWebClient.cs | 63 ++++++++++++------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/BaseSpace.SDK/Infrastructure/JsonWebClient.cs b/BaseSpace.SDK/Infrastructure/JsonWebClient.cs index a4e6b43..0c37902 100644 --- a/BaseSpace.SDK/Infrastructure/JsonWebClient.cs +++ b/BaseSpace.SDK/Infrastructure/JsonWebClient.cs @@ -14,40 +14,54 @@ namespace Illumina.BaseSpace.SDK { public class JsonWebClient : IWebClient { - private readonly JsonServiceClient client; + private JsonServiceClient client; - private readonly ILog logger; + private ILog logger; - private readonly IClientSettings settings; + private IClientSettings settings; + + internal void RespawnClient() + { + if (_clientFactoryMethod != null) + _clientFactoryMethod(); + } + + + private readonly Action _clientFactoryMethod; public JsonWebClient(IClientSettings settings, IRequestOptions defaultOptions = null) { - if (settings == null) + _clientFactoryMethod = () => { - throw new ArgumentNullException("settings"); - } + if (settings == null) + { + throw new ArgumentNullException("settings"); + } + + this.settings = settings; + DefaultRequestOptions = defaultOptions ?? new RequestOptions(); + logger = LogManager.GetCurrentClassLogger(); - this.settings = settings; - DefaultRequestOptions = defaultOptions ?? new RequestOptions(); - logger = LogManager.GetCurrentClassLogger(); + // call something on this object so it gets initialized in single threaded context + HttpEncoder.Default.SerializeToString(); - // call something on this object so it gets initialized in single threaded context - HttpEncoder.Default.SerializeToString(); + //need to add the following call for Mono -- https://bugzilla.xamarin.com/show_bug.cgi?id=12565 + if (Helpers.IsRunningOnMono()) + { + HttpEncoder.Current = HttpEncoder.Default; + } - //need to add the following call for Mono -- https://bugzilla.xamarin.com/show_bug.cgi?id=12565 - if (Helpers.IsRunningOnMono()) - { - HttpEncoder.Current = HttpEncoder.Default; - } + HttpEncoder.Current.SerializeToString(); - HttpEncoder.Current.SerializeToString(); + client = new JsonServiceClient(settings.BaseSpaceApiUrl); + client.LocalHttpWebRequestFilter += WebRequestFilter; - client = new JsonServiceClient(settings.BaseSpaceApiUrl); - client.LocalHttpWebRequestFilter += WebRequestFilter; + if (settings.TimeoutMin > 0) + client.Timeout = TimeSpan.FromMinutes(settings.TimeoutMin); + }; - if (settings.TimeoutMin > 0) - client.Timeout = TimeSpan.FromMinutes(settings.TimeoutMin); + _clientFactoryMethod(); } static JsonWebClient() @@ -103,7 +117,12 @@ public TReturn Send(AbstractRequest request, IRequestOptions o TReturn result = null; options = options ?? DefaultRequestOptions; - RetryLogic.DoWithRetry(options.RetryAttempts, request.GetName(), () => result = request.GetSendFunc(client)(), logger); + RetryLogic.DoWithRetry(options.RetryAttempts, request.GetName(), () => result = request.GetSendFunc(client)(), logger + ,retryHandler: (exc) => + { + RespawnClient(); + return RetryLogic.GenericRetryHandler(exc); + }); return result; } catch (WebServiceException webx) From f87829289c114fdb121308448e22d2bd8f6ab75b Mon Sep 17 00:00:00 2001 From: gvessere Date: Wed, 19 Nov 2014 13:11:48 -0800 Subject: [PATCH 2/3] Unit test for previous change --- .../BaseSpace.SDK.Tests.csproj | 3 + BaseSpace.SDK.Tests/JsonWebClientTests.cs | 58 +++++++++++++++++++ BaseSpace.SDK.Tests/packages.config | 1 + .../Infrastructure/BaseSpaceClientSettings.cs | 7 ++- BaseSpace.SDK/Infrastructure/JsonWebClient.cs | 9 +-- BaseSpace.SDK/Interfaces/IClientSettings.cs | 2 +- BaseSpace.SDK/Interfaces/IRequestOptions.cs | 9 ++- BaseSpace.SDK/Properties/AssemblyInfo.cs | 2 +- BaseSpace.SDK/Types/RequestOptions.cs | 7 ++- 9 files changed, 85 insertions(+), 13 deletions(-) diff --git a/BaseSpace.SDK.Tests/BaseSpace.SDK.Tests.csproj b/BaseSpace.SDK.Tests/BaseSpace.SDK.Tests.csproj index 81dcd90..98f8dc7 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..e408eaf 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] + public void CanRespawnClientAtEachRetry() + { + var setting = new BaseSpaceClientSettings() + { + BaseSpaceApiUrl = "https://api.basespace.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 bfe7256..a3250e8 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"; @@ -43,6 +44,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 0c37902..115a31c 100644 --- a/BaseSpace.SDK/Infrastructure/JsonWebClient.cs +++ b/BaseSpace.SDK/Infrastructure/JsonWebClient.cs @@ -1,5 +1,6 @@ using System; using System.Net; +using System.Runtime.Remoting.Messaging; using System.Web.Util; using Common.Logging; using Illumina.BaseSpace.SDK.Deserialization; @@ -14,20 +15,20 @@ namespace Illumina.BaseSpace.SDK { public class JsonWebClient : IWebClient { - private JsonServiceClient client; + internal JsonServiceClient client; private ILog logger; private IClientSettings settings; - internal void RespawnClient() + public virtual void RespawnClient() { if (_clientFactoryMethod != null) _clientFactoryMethod(); } - private readonly Action _clientFactoryMethod; + internal readonly Action _clientFactoryMethod; public JsonWebClient(IClientSettings settings, IRequestOptions defaultOptions = null) @@ -118,7 +119,7 @@ public TReturn Send(AbstractRequest request, IRequestOptions o options = options ?? DefaultRequestOptions; RetryLogic.DoWithRetry(options.RetryAttempts, request.GetName(), () => result = request.GetSendFunc(client)(), logger - ,retryHandler: (exc) => + , retryIntervalBaseSecs:options.RetryPowerBase,retryHandler: (exc) => { RespawnClient(); return RetryLogic.GenericRetryHandler(exc); diff --git a/BaseSpace.SDK/Interfaces/IClientSettings.cs b/BaseSpace.SDK/Interfaces/IClientSettings.cs index bb51215..70f2350 100644 --- a/BaseSpace.SDK/Interfaces/IClientSettings.cs +++ b/BaseSpace.SDK/Interfaces/IClientSettings.cs @@ -17,6 +17,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; } + } } From f7d79aa3c43f26c66ccd3058e1a65f67caeaa618 Mon Sep 17 00:00:00 2001 From: gvessere Date: Wed, 19 Nov 2014 13:25:37 -0800 Subject: [PATCH 3/3] disable test --- BaseSpace.SDK.Tests/JsonWebClientTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BaseSpace.SDK.Tests/JsonWebClientTests.cs b/BaseSpace.SDK.Tests/JsonWebClientTests.cs index 0408485..99fba71 100644 --- a/BaseSpace.SDK.Tests/JsonWebClientTests.cs +++ b/BaseSpace.SDK.Tests/JsonWebClientTests.cs @@ -37,7 +37,7 @@ public void RequestOptionsAreProperlyUsed() } - [Fact] + [Fact(Skip = "disabled since it needs token and session")] public void CanRespawnClientAtEachRetry() { var setting = new BaseSpaceClientSettings()