From 1f5010280be3f161fd1e4dcd1687f21f61eb195a Mon Sep 17 00:00:00 2001 From: Razvan Goga Date: Tue, 30 Aug 2022 23:19:58 +0200 Subject: [PATCH] added ServiceState based on replicas state surfaced ServiceState in dashboard made dashboard links more self-evident --- .../Dashboard/Pages/Index.razor | 21 ++++++-- src/Microsoft.Tye.Hosting/Model/Service.cs | 51 ++++++++++++++++++ test/UnitTests/Microsoft.Tye.UnitTests.csproj | 8 +++ test/UnitTests/ServiceUnitTests.cs | 52 +++++++++++++++++++ 4 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 test/UnitTests/ServiceUnitTests.cs diff --git a/src/Microsoft.Tye.Hosting/Dashboard/Pages/Index.razor b/src/Microsoft.Tye.Hosting/Dashboard/Pages/Index.razor index cf06ba18..c63736df 100644 --- a/src/Microsoft.Tye.Hosting/Dashboard/Pages/Index.razor +++ b/src/Microsoft.Tye.Hosting/Dashboard/Pages/Index.razor @@ -12,13 +12,14 @@ + - + @@ -26,7 +27,11 @@ { var logsPath = $"logs/{service.Description.Name}"; var servicePath = $"services/{service.Description.Name}"; + var serviceState = service.State; + - + } } @@ -102,6 +107,16 @@ private List _subscriptions = new List(); + string GetServiceStateClass(ServiceState serviceState) => serviceState switch + { + ServiceState.Starting => "badge-secondary", + ServiceState.Started => "badge-success", + ServiceState.Degraded => "badge-danger", + ServiceState.Failed => "badge-warning", + ServiceState.Stopped => "badge-light", + _ => "badge-dark" + }; + string GetUrl(ServiceBinding b) { return $"{(b.Protocol ?? "tcp")}://{b.Host ?? "localhost"}:{b.Port}"; diff --git a/src/Microsoft.Tye.Hosting/Model/Service.cs b/src/Microsoft.Tye.Hosting/Model/Service.cs index 265a1c6c..d064e475 100644 --- a/src/Microsoft.Tye.Hosting/Model/Service.cs +++ b/src/Microsoft.Tye.Hosting/Model/Service.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Reactive.Subjects; namespace Microsoft.Tye.Hosting.Model @@ -83,5 +84,55 @@ namespace Microsoft.Tye.Hosting.Model public Subject Logs { get; } = new Subject(); public Subject ReplicaEvents { get; } = new Subject(); + + public ServiceState State + { + get + { + var replicaStates = Replicas.Values.Select(r => r.State); + int replicaCount = replicaStates.Count(); + + + if (replicaCount == 0) + return ServiceState.Unknown; + + if (replicaStates.Any(r => r == ReplicaState.Added)) + return ServiceState.Starting; + + if (replicaStates.All(r => r == ReplicaState.Started || r == ReplicaState.Ready || r == ReplicaState.Healthy)) + return ServiceState.Started; + + if (replicaCount == 1) + { + ReplicaState? replicaState = replicaStates.Single(); + + if (replicaState == ReplicaState.Removed) + return ServiceState.Failed; + + if (replicaState == ReplicaState.Stopped) + return ServiceState.Stopped; + } + else + { + if (replicaStates.All(r => r == ReplicaState.Stopped)) + return ServiceState.Stopped; + + if (replicaStates.Any(r => r == ReplicaState.Removed || r == ReplicaState.Stopped)) + return ServiceState.Degraded; + } + + return ServiceState.Unknown; + } + } + } + + public enum ServiceState + { + Unknown, + Starting, + Started, + Degraded, + Failed, + Stopped } } diff --git a/test/UnitTests/Microsoft.Tye.UnitTests.csproj b/test/UnitTests/Microsoft.Tye.UnitTests.csproj index d2addfef..7fbea20f 100644 --- a/test/UnitTests/Microsoft.Tye.UnitTests.csproj +++ b/test/UnitTests/Microsoft.Tye.UnitTests.csproj @@ -9,6 +9,14 @@ XUnit + + 10.0 + + + + 10.0 + + diff --git a/test/UnitTests/ServiceUnitTests.cs b/test/UnitTests/ServiceUnitTests.cs new file mode 100644 index 00000000..ed64dbba --- /dev/null +++ b/test/UnitTests/ServiceUnitTests.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using Microsoft.Tye.Hosting.Model; +using Xunit; + +namespace Microsoft.Tye.UnitTests +{ + public class ServiceUnitTests + { + [Theory] + [MemberData(nameof(ServiceStateTestData))] + public void ServiceStateIsBasedOnReplicaStates(ServiceState expected, List replicaStates) + { + Service service = new(new ServiceDescription("test", null), ServiceSource.Unknown); + + for (int i = 0; i < replicaStates.Count; i++) + { + string replicaName = i.ToString(); + + service.Replicas.TryAdd(replicaName, new ReplicaStatus(service, replicaName) + { + State = replicaStates[i], + }); + } + + Assert.Equal(expected, service.State); + + } + + public static IEnumerable ServiceStateTestData => + new List + { + //no replica - should not happen + new object[] { ServiceState.Unknown, new List() }, + + //one replica + new object[] { ServiceState.Starting, new List() { ReplicaState.Added } }, + new object[] { ServiceState.Started, new List() { ReplicaState.Started } }, + new object[] { ServiceState.Started, new List() { ReplicaState.Ready } }, + new object[] { ServiceState.Started, new List() { ReplicaState.Healthy } }, + new object[] { ServiceState.Failed, new List() { ReplicaState.Removed } }, + new object[] { ServiceState.Stopped, new List() { ReplicaState.Stopped } }, + + //multiple replicas + new object[] { ServiceState.Starting, new List() { ReplicaState.Added, ReplicaState.Started, ReplicaState.Ready, ReplicaState.Healthy } }, + new object[] { ServiceState.Started, new List() { ReplicaState.Started, ReplicaState.Ready, ReplicaState.Healthy } }, + new object[] { ServiceState.Degraded, new List() { ReplicaState.Removed, ReplicaState.Started, ReplicaState.Ready, ReplicaState.Healthy } }, + new object[] { ServiceState.Degraded, new List() { ReplicaState.Stopped, ReplicaState.Started, ReplicaState.Ready, ReplicaState.Healthy } }, + new object[] { ServiceState.Degraded, new List() { ReplicaState.Removed, ReplicaState.Stopped, ReplicaState.Started, ReplicaState.Ready, ReplicaState.Healthy } }, + new object[] { ServiceState.Stopped, new List() { ReplicaState.Stopped, ReplicaState.Stopped, ReplicaState.Stopped } }, + }; + } +}
Name Type Source Bindings Replicas RestartsLogs
+ @serviceState + @if(service.ServiceType == ServiceType.External) { @@ -34,7 +39,7 @@ } else { - @service.Description.Name + @service.Description.Name } @@ -91,7 +96,7 @@ { @service.Replicas.Count/@service.Description.Replicas @service.RestartsViewLogs | Metrics