Skip to content

Commit

Permalink
Added Polly retry logic
Browse files Browse the repository at this point in the history
Added Local Network availability check
Added more logging
  • Loading branch information
Ishai Hachlili committed Feb 1, 2020
1 parent b57d567 commit 15c01a9
Show file tree
Hide file tree
Showing 11 changed files with 329 additions and 34 deletions.
54 changes: 53 additions & 1 deletion ConsoleTestApp/App.config
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
Expand All @@ -9,4 +9,56 @@
<add key="SuspendScene" value="scene.laptop_off" />
<add key="ResumeScene" value="scene.laptop_on" />
</appSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Configuration.Binder" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Configuration" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Options.ConfigurationExtensions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.Configuration" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
62 changes: 62 additions & 0 deletions ConsoleTestApp/ConsoleTestApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,77 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.3.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.Binder, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.3.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.3.1.1\lib\net461\Microsoft.Extensions.DependencyInjection.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.1\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.3.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Configuration, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Configuration.3.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.Configuration.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Console, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Console.3.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.Console.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Options, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Options.3.1.1\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Options.ConfigurationExtensions, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Options.ConfigurationExtensions.3.1.1\lib\netstandard2.0\Microsoft.Extensions.Options.ConfigurationExtensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Primitives, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Primitives.3.1.1\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Polly, Version=7.0.0.0, Culture=neutral, PublicKeyToken=c8a3ffc3f8f825cc, processorArchitecture=MSIL">
<HintPath>..\packages\Polly.7.2.0\lib\net472\Polly.dll</HintPath>
</Reference>
<Reference Include="Refit, Version=5.0.0.0, Culture=neutral, PublicKeyToken=2f9b1262776509f5, processorArchitecture=MSIL">
<HintPath>..\packages\Refit.5.0.23\lib\net461\Refit.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.2\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
Expand Down
18 changes: 13 additions & 5 deletions ConsoleTestApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using HomeAssistantClient;
using System;
using System.Configuration;

namespace ConsoleTestApp
Expand All @@ -7,11 +8,18 @@ class Program
{
static void Main(string[] args)
{
var baseUrl = ConfigurationManager.AppSettings["BaseUrl"];
var token = ConfigurationManager.AppSettings["Token"];
var restApiClient = new RestApiClient(baseUrl, token);
var resumeScene = ConfigurationManager.AppSettings["ResumeScene"];
restApiClient.ActivateScene(resumeScene);
try
{
var baseUrl = ConfigurationManager.AppSettings["BaseUrl"];
var token = ConfigurationManager.AppSettings["Token"];
var restApiClient = new RestApiClient(baseUrl, token, null);
var resumeScene = ConfigurationManager.AppSettings["ResumeSuspendScene"];
restApiClient.ActivateScene(resumeScene);
}
catch (Exception ex)
{
}

}
}
}
1 change: 1 addition & 0 deletions ConsoleTestApp/packages.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net472" />
<package id="Polly" version="7.2.0" targetFramework="net472" />
<package id="Refit" version="5.0.23" targetFramework="net472" />
</packages>
2 changes: 2 additions & 0 deletions HomeAssistantClient/HomeAssistantClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.1" />
<PackageReference Include="Polly" Version="7.2.0" />
<PackageReference Include="Refit" Version="5.0.23" />
</ItemGroup>

Expand Down
3 changes: 2 additions & 1 deletion HomeAssistantClient/IHomeAssistantApi.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using HomeAssistantClient.Model;
using Refit;
using System.Net.Http;
using System.Threading.Tasks;

namespace HomeAssistantClient
{
public interface IHomeAssistantApi
{
[Post("/api/services/scene/turn_on")]
Task ActivateScene([Body]Entity entity, [Header("Authorization")] string authorization);
Task<HttpResponseMessage> ActivateScene([Body]Entity entity, [Header("Authorization")] string authorization);
}
}
120 changes: 116 additions & 4 deletions HomeAssistantClient/RestApiClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
using HomeAssistantClient.Model;
using Refit;
using Polly;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using System.Net.NetworkInformation;
using System.Net;
using System.Linq;

namespace HomeAssistantClient
{
Expand All @@ -8,10 +16,14 @@ public class RestApiClient
private IHomeAssistantApi _apiClient;
private string _baseUrl;
private string _token;
public RestApiClient(string baseUrl, string token)
private ILogger _logger;
private static readonly int _numberOfRetries = 15;

public RestApiClient(string baseUrl, string token, ILogger logger)
{
_baseUrl = baseUrl;
_token = token;
_logger = logger;
}
public IHomeAssistantApi ApiClient {
get
Expand All @@ -22,9 +34,109 @@ public IHomeAssistantApi ApiClient {
}
public void ActivateScene(string sceneId)
{
//var baseUrl = ConfigurationManager.AppSettings["BaseUrl"];
//var token = ConfigurationManager.AppSettings["Token"];
ApiClient.ActivateScene(new Entity { Id = sceneId }, _token).Wait();
_logger?.LogTrace($"{nameof(ActivateScene)} - SceneId:{sceneId} - Start");

HttpStatusCode[] httpStatusCodesWorthRetrying =
{
HttpStatusCode.RequestTimeout, //408
HttpStatusCode.NotFound, //404
HttpStatusCode.InternalServerError, //500
HttpStatusCode.BadGateway, //502
HttpStatusCode.ServiceUnavailable, //503
HttpStatusCode.GatewayTimeout //504
};


Policy.Handle<HttpRequestException>()
.Or<TaskCanceledException>()
.OrResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
.WaitAndRetryAsync(_numberOfRetries, retryAttempt =>
TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
(response, timeSpan, context) =>
{
_logger?.LogError(response.Exception, $"Retry wait for {timeSpan.TotalSeconds} after {response.Result.StatusCode} - {response.Exception.Message}");
}
)
.ExecuteAsync(async () => await CallActivateSceneApi(sceneId))
.Wait();

_logger?.LogTrace($"{nameof(ActivateScene)} - SceneId:{sceneId} - Finished");
}

private async Task<HttpResponseMessage> CallActivateSceneApi(string sceneId)
{
_logger?.LogTrace($"{nameof(ActivateScene)} - SceneId:{sceneId} - Start");

try
{
for (var i=0; i < 20; i++)
{

_logger?.LogTrace($"{nameof(ActivateScene)} - SceneId:{sceneId} - Check Network {i}");
if (IsNetworkAvailable())
{
break;
}
Task.Delay(TimeSpan.FromMilliseconds(500)).Wait();
}
}
catch (Exception ex)
{
_logger?.LogError(ex, $"{nameof(CallActivateSceneApi)} - SceneId:{sceneId} - Wait For Network - {ex.ToString()}");
}

try
{
var r = await ApiClient.ActivateScene(new Entity { Id = sceneId }, _token);
_logger?.LogTrace($"{nameof(CallActivateSceneApi)} - SceneId:{sceneId} - Finished");
return r;
}
catch (Exception ex)
{
_logger?.LogError(ex, $"{nameof(CallActivateSceneApi)} - SceneId:{sceneId} - {ex.ToString()}");
throw ex;
}

}

/// <summary>
/// Indicates whether any network connection is available.
/// Filter connections below a specified speed, as well as virtual network cards.
/// </summary>
/// <param name="minimumSpeed">The minimum speed required. Passing 0 will not filter connection using speed.</param>
/// <returns>
/// <c>true</c> if a network connection is available; otherwise, <c>false</c>.
/// </returns>
public static bool IsNetworkAvailable(long minimumSpeed=0)
{
if (!NetworkInterface.GetIsNetworkAvailable())
return false;

foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
{
// discard because of standard reasons
if ((ni.OperationalStatus != OperationalStatus.Up) ||
(ni.NetworkInterfaceType == NetworkInterfaceType.Loopback) ||
(ni.NetworkInterfaceType == NetworkInterfaceType.Tunnel))
continue;

// this allow to filter modems, serial, etc.
// I use 10000000 as a minimum speed for most cases
if (ni.Speed < minimumSpeed)
continue;

// discard virtual cards (virtual box, virtual pc, etc.)
if ((ni.Description.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) >= 0) ||
(ni.Name.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) >= 0))
continue;

// discard "Microsoft Loopback Adapter", it will not show as NetworkInterfaceType.Loopback but as Ethernet Card.
if (ni.Description.Equals("Microsoft Loopback Adapter", StringComparison.OrdinalIgnoreCase))
continue;

return true;
}
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,15 @@
<StartupObject>HomeAssistantPowerStateService.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Polly, Version=7.0.0.0, Culture=neutral, PublicKeyToken=c8a3ffc3f8f825cc, processorArchitecture=MSIL">
<HintPath>..\packages\Polly.7.2.0\lib\net472\Polly.dll</HintPath>
</Reference>
<Reference Include="Refit, Version=5.0.0.0, Culture=neutral, PublicKeyToken=2f9b1262776509f5, processorArchitecture=MSIL">
<HintPath>..\packages\Refit.5.0.23\lib\net461\Refit.dll</HintPath>
</Reference>
Expand All @@ -93,6 +99,7 @@
<Compile Include="HomeAssistantService.Designer.cs">
<DependentUpon>HomeAssistantService.cs</DependentUpon>
</Compile>
<Compile Include="TextFileLogger.cs" />
<Compile Include="Program.cs" />
<Compile Include="ProjectInstaller.cs">
<SubType>Component</SubType>
Expand Down
Loading

0 comments on commit 15c01a9

Please sign in to comment.