昨天問題是因為在執行Fortune-Teller-UI環境變數的SET BUILD=LOCAL 沒有設定到
設定好之後執行Fortune-Teller-UI,打開http://localhost:5555 在打開Hystrix dashboard就可以看到圖表了
注意看可以看到上面圖表中一個黃色Timeout,這是因為我把後端的Fortune-Teller-Service關掉了,
這時候Hystrix command會自動幫我們執行服務出現錯誤時候的fallback method,就是下圖紅框的部分
先到appsettings.json看hystrix的相關參數
"hystrix": {
"collapser": {
"FortuneServiceCollapser": {
"timerDelayInMilliseconds": 250
}
},
"stream": {
"validate_certificates": false
},
"command": {
"FortuneService": {
"threadPoolKeyOverride": "FortuneServiceTPool"
}
}
}
collapser:HystrixCollapser的設定
command: HystrixCommand的設定
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging();
services.AddDiscoveryClient(Configuration);
// The Fortune service itself, calls the REST APIs to get random fortunes
services.AddSingleton<IFortuneService, FortuneService>();
// A Hystrix command that makes use of the FortuneService
services.AddHystrixCommand<FortuneServiceCommand>("FortuneService", Configuration);
services.AddTransient<IFakeService1, FakeService1>();
services.AddTransient<IFakeService2, FakeService2>();
services.AddTransient<IFakeServices3, FakeService3>();
// A Hystrix collapser that makes use of the FortuneService above to get a Fortune.
services.AddHystrixCollapser<IFortuneServiceCollapser, FortuneServiceCollapser>("FortuneServiceCollapser", Configuration);
// Add framework services.
services.AddMvc();
services.AddHystrixMetricsStream(Configuration);
}
需要注意的有
先來看一下HystrxCommand的interface
public class HystrixCommand<TResult> : AbstractCommand<TResult>, IHystrixExecutable<TResult>, IHystrixObservable<TResult>, IHystrixInvokable
{
protected readonly Func<TResult> _run;
protected readonly Func<TResult> _fallback;
public HystrixCommand(IHystrixCommandGroupKey group, Func<TResult> run = null, Func<TResult> fallback = null, ILogger logger = null);
public HystrixCommand(IHystrixCommandOptions commandOptions, Func<TResult> run = null, Func<TResult> fallback = null, ILogger logger = null);
public HystrixCommand(IHystrixCommandGroupKey group, IHystrixThreadPoolKey threadPool, Func<TResult> run = null, Func<TResult> fallback = null, ILogger logger = null);
public HystrixCommand(IHystrixCommandGroupKey group, int executionIsolationThreadTimeoutInMilliseconds, Func<TResult> run = null, Func<TResult> fallback = null, ILogger logger = null);
public HystrixCommand(IHystrixCommandGroupKey group, IHystrixThreadPoolKey threadPool, int executionIsolationThreadTimeoutInMilliseconds, Func<TResult> run = null, Func<TResult> fallback = null, ILogger logger = null);
public HystrixCommand(IHystrixCommandGroupKey group, IHystrixCommandKey key, IHystrixThreadPoolKey threadPoolKey, IHystrixCircuitBreaker circuitBreaker, IHystrixThreadPool threadPool, IHystrixCommandOptions commandOptionsDefaults, IHystrixThreadPoolOptions threadPoolOptionsDefaults, HystrixCommandMetrics metrics, SemaphoreSlim fallbackSemaphore, SemaphoreSlim executionSemaphore, HystrixOptionsStrategy optionsStrategy, HystrixCommandExecutionHook executionHook, Func<TResult> run, Func<TResult> fallback, ILogger logger = null);
public TResult Execute();
public Task<TResult> ExecuteAsync();
public Task<TResult> ExecuteAsync(CancellationToken token);
public IObservable<TResult> Observe();
public IObservable<TResult> Observe(CancellationToken token);
public IObservable<TResult> ToObservable();
protected override TResult DoFallback();
protected override TResult DoRun();
protected virtual TResult Run();
[AsyncStateMachine(typeof(HystrixCommand<>.<RunAsync>d__17))]
protected virtual Task<TResult> RunAsync();
protected virtual TResult RunFallback();
[AsyncStateMachine(typeof(HystrixCommand<>.<RunFallbackAsync>d__18))]
protected virtual Task<TResult> RunFallbackAsync();
注意可以複寫的方法有
接著看實作HystrixCommand的FortuneServiceCommand.cs
using Microsoft.Extensions.Logging;
using Steeltoe.CircuitBreaker.Hystrix;
using System.Threading.Tasks;
namespace Fortune_Teller_UI.Services
{
public class FortuneServiceCommand : HystrixCommand<Fortune>
{
IFortuneService _fortuneService;
ILogger<FortuneServiceCommand> _logger;
public FortuneServiceCommand(IHystrixCommandOptions options, IFortuneService fortuneService, ILogger<FortuneServiceCommand> logger) : base(options)
{
_fortuneService = fortuneService;
_logger = logger;
IsFallbackUserDefined = true;
}
public async Task<Fortune> RandomFortune()
{
return await ExecuteAsync();
}
protected override async Task<Fortune> RunAsync()
{
var result = await _fortuneService.RandomFortuneAsync();
_logger.LogInformation("Run: {0}", result);
return result;
}
protected override async Task<Fortune> RunFallbackAsync()
{
_logger.LogInformation("RunFallback");
return await Task.FromResult<Fortune>(new Fortune() { Id = 9999, Text = "You will have a happy day!" });
}
}
}
Constructor有傳入IHystrixCommandOptions, 可以藉由更改options來更改Command的設定
實際上使用的FortuneService也會在這邊注入,而在這裡複寫了HystrixCommand的兩個非同步方法,
RunAsync()跟RunFallbackAsync(),可以看到一般FortuneService放在RunAsunc()裡面使用,而RunFallbackAsync則是塞了一個假資料作為服務狀態為open(斷路不正常)時候的替代方案,那怎麼調用這兩個方法,
這邊可以看到有一個新增的方法RandomFortune()作為外部調用FortuneServiceCommand的方法,然後由ExecuteAsync()來決定觸發RunAsync或是RunFallbackAsync