diff options
author | Jan Tattermusch <jtattermusch@google.com> | 2015-07-14 20:29:21 -0700 |
---|---|---|
committer | Jan Tattermusch <jtattermusch@google.com> | 2015-07-15 10:29:57 -0700 |
commit | 5253467d5c41e3b2123cf894afdccf6340d225fb (patch) | |
tree | b13dd29cd2a0ebf22695effeb9516a7222eeea5f /src/csharp/Grpc.HealthCheck | |
parent | e6d12d335c160b02a8f866775ffe953962f5988f (diff) |
C# health checking support
Diffstat (limited to 'src/csharp/Grpc.HealthCheck')
-rw-r--r-- | src/csharp/Grpc.HealthCheck/.gitignore | 2 | ||||
-rw-r--r-- | src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj | 74 | ||||
-rw-r--r-- | src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec | 28 | ||||
-rw-r--r-- | src/csharp/Grpc.HealthCheck/Health.cs | 687 | ||||
-rw-r--r-- | src/csharp/Grpc.HealthCheck/HealthGrpc.cs | 78 | ||||
-rw-r--r-- | src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs | 132 | ||||
-rw-r--r-- | src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs | 12 | ||||
-rw-r--r-- | src/csharp/Grpc.HealthCheck/packages.config | 5 | ||||
-rw-r--r-- | src/csharp/Grpc.HealthCheck/proto/health.proto | 52 |
9 files changed, 1070 insertions, 0 deletions
diff --git a/src/csharp/Grpc.HealthCheck/.gitignore b/src/csharp/Grpc.HealthCheck/.gitignore new file mode 100644 index 0000000000..1746e3269e --- /dev/null +++ b/src/csharp/Grpc.HealthCheck/.gitignore @@ -0,0 +1,2 @@ +bin +obj diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj new file mode 100644 index 0000000000..6d37b37deb --- /dev/null +++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{AA5E328A-8835-49D7-98ED-C29F2B3049F0}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Grpc.HealthCheck</RootNamespace> + <AssemblyName>Grpc.HealthCheck</AssemblyName> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Google.ProtocolBuffers"> + <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath> + </Reference> + <Reference Include="Google.ProtocolBuffers.Serialization"> + <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Interactive.Async"> + <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath> + </Reference> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="HealthServiceImpl.cs" /> + <Compile Include="Health.cs" /> + <Compile Include="HealthGrpc.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + <None Include="proto\health.proto" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj"> + <Project>{ccc4440e-49f7-4790-b0af-feabb0837ae7}</Project> + <Name>Grpc.Core</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec new file mode 100644 index 0000000000..c774133ab0 --- /dev/null +++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<package> + <metadata> + <id>Grpc.HealthCheck</id> + <title>gRPC C# Healthchecking</title> + <summary>Implementation of gRPC health service</summary> + <description>Example implementation of grpc.health.v1alpha service that can be used for health-checking.</description> + <version>0.6.0</version> + <authors>Google Inc.</authors> + <owners>grpc-packages</owners> + <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl> + <projectUrl>https://github.com/grpc/grpc</projectUrl> + <requireLicenseAcceptance>false</requireLicenseAcceptance> + <copyright>Copyright 2015, Google Inc.</copyright> + <tags>gRPC health check</tags> + <dependencies> + <dependency id="Google.ProtocolBuffers" version="2.4.1.555" /> + <dependency id="Grpc.Core" version="0.6.0" /> + <dependency id="Ix-Async" version="1.2.3" /> + </dependencies> + </metadata> + <files> + <file src="bin/Release/Grpc.HealthCheck.dll" target="lib/net45" /> + <file src="bin/Release/Grpc.HealthCheck.pdb" target="lib/net45" /> + <file src="bin/Release/Grpc.HealthCheck.xml" target="lib/net45" /> + <file src="**\*.cs" target="src" /> + </files> +</package> diff --git a/src/csharp/Grpc.HealthCheck/Health.cs b/src/csharp/Grpc.HealthCheck/Health.cs new file mode 100644 index 0000000000..361382d4bd --- /dev/null +++ b/src/csharp/Grpc.HealthCheck/Health.cs @@ -0,0 +1,687 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: health.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.ProtocolBuffers; +using pbc = global::Google.ProtocolBuffers.Collections; +using pbd = global::Google.ProtocolBuffers.Descriptors; +using scg = global::System.Collections.Generic; +namespace Grpc.Health.V1Alpha { + + namespace Proto { + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public static partial class Health { + + #region Extension registration + public static void RegisterAllExtensions(pb::ExtensionRegistry registry) { + } + #endregion + #region Static variables + internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor; + internal static pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckRequest.Builder> internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable; + internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor; + internal static pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckResponse, global::Grpc.Health.V1Alpha.HealthCheckResponse.Builder> internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable; + #endregion + #region Descriptor + public static pbd::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbd::FileDescriptor descriptor; + + static Health() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CgxoZWFsdGgucHJvdG8SE2dycGMuaGVhbHRoLnYxYWxwaGEiMwoSSGVhbHRo", + "Q2hlY2tSZXF1ZXN0EgwKBGhvc3QYASABKAkSDwoHc2VydmljZRgCIAEoCSKZ", + "AQoTSGVhbHRoQ2hlY2tSZXNwb25zZRJGCgZzdGF0dXMYASABKA4yNi5ncnBj", + "LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVzcG9uc2UuU2VydmluZ1N0", + "YXR1cyI6Cg1TZXJ2aW5nU3RhdHVzEgsKB1VOS05PV04QABILCgdTRVJWSU5H", + "EAESDwoLTk9UX1NFUlZJTkcQAjJkCgZIZWFsdGgSWgoFQ2hlY2sSJy5ncnBj", + "LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVxdWVzdBooLmdycGMuaGVh", + "bHRoLnYxYWxwaGEuSGVhbHRoQ2hlY2tSZXNwb25zZUIWqgITR3JwYy5IZWFs", + "dGguVjFBbHBoYQ==")); + pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) { + descriptor = root; + internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor = Descriptor.MessageTypes[0]; + internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable = + new pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckRequest.Builder>(internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor, + new string[] { "Host", "Service", }); + internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor = Descriptor.MessageTypes[1]; + internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable = + new pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckResponse, global::Grpc.Health.V1Alpha.HealthCheckResponse.Builder>(internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor, + new string[] { "Status", }); + pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance(); + RegisterAllExtensions(registry); + return registry; + }; + pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbd::FileDescriptor[] { + }, assigner); + } + #endregion + + } + } + #region Messages + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class HealthCheckRequest : pb::GeneratedMessage<HealthCheckRequest, HealthCheckRequest.Builder> { + private HealthCheckRequest() { } + private static readonly HealthCheckRequest defaultInstance = new HealthCheckRequest().MakeReadOnly(); + private static readonly string[] _healthCheckRequestFieldNames = new string[] { "host", "service" }; + private static readonly uint[] _healthCheckRequestFieldTags = new uint[] { 10, 18 }; + public static HealthCheckRequest DefaultInstance { + get { return defaultInstance; } + } + + public override HealthCheckRequest DefaultInstanceForType { + get { return DefaultInstance; } + } + + protected override HealthCheckRequest ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable<HealthCheckRequest, HealthCheckRequest.Builder> InternalFieldAccessors { + get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable; } + } + + public const int HostFieldNumber = 1; + private bool hasHost; + private string host_ = ""; + public bool HasHost { + get { return hasHost; } + } + public string Host { + get { return host_; } + } + + public const int ServiceFieldNumber = 2; + private bool hasService; + private string service_ = ""; + public bool HasService { + get { return hasService; } + } + public string Service { + get { return service_; } + } + + public override bool IsInitialized { + get { + return true; + } + } + + public override void WriteTo(pb::ICodedOutputStream output) { + CalcSerializedSize(); + string[] field_names = _healthCheckRequestFieldNames; + if (hasHost) { + output.WriteString(1, field_names[0], Host); + } + if (hasService) { + output.WriteString(2, field_names[1], Service); + } + UnknownFields.WriteTo(output); + } + + private int memoizedSerializedSize = -1; + public override int SerializedSize { + get { + int size = memoizedSerializedSize; + if (size != -1) return size; + return CalcSerializedSize(); + } + } + + private int CalcSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasHost) { + size += pb::CodedOutputStream.ComputeStringSize(1, Host); + } + if (hasService) { + size += pb::CodedOutputStream.ComputeStringSize(2, Service); + } + size += UnknownFields.SerializedSize; + memoizedSerializedSize = size; + return size; + } + public static HealthCheckRequest ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static HealthCheckRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static HealthCheckRequest ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static HealthCheckRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static HealthCheckRequest ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static HealthCheckRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input) { + return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); + } + public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); + } + public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + private HealthCheckRequest MakeReadOnly() { + return this; + } + + public static Builder CreateBuilder() { return new Builder(); } + public override Builder ToBuilder() { return CreateBuilder(this); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(HealthCheckRequest prototype) { + return new Builder(prototype); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Builder : pb::GeneratedBuilder<HealthCheckRequest, Builder> { + protected override Builder ThisBuilder { + get { return this; } + } + public Builder() { + result = DefaultInstance; + resultIsReadOnly = true; + } + internal Builder(HealthCheckRequest cloneFrom) { + result = cloneFrom; + resultIsReadOnly = true; + } + + private bool resultIsReadOnly; + private HealthCheckRequest result; + + private HealthCheckRequest PrepareBuilder() { + if (resultIsReadOnly) { + HealthCheckRequest original = result; + result = new HealthCheckRequest(); + resultIsReadOnly = false; + MergeFrom(original); + } + return result; + } + + public override bool IsInitialized { + get { return result.IsInitialized; } + } + + protected override HealthCheckRequest MessageBeingBuilt { + get { return PrepareBuilder(); } + } + + public override Builder Clear() { + result = DefaultInstance; + resultIsReadOnly = true; + return this; + } + + public override Builder Clone() { + if (resultIsReadOnly) { + return new Builder(result); + } else { + return new Builder().MergeFrom(result); + } + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.Descriptor; } + } + + public override HealthCheckRequest DefaultInstanceForType { + get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance; } + } + + public override HealthCheckRequest BuildPartial() { + if (resultIsReadOnly) { + return result; + } + resultIsReadOnly = true; + return result.MakeReadOnly(); + } + + public override Builder MergeFrom(pb::IMessage other) { + if (other is HealthCheckRequest) { + return MergeFrom((HealthCheckRequest) other); + } else { + base.MergeFrom(other); + return this; + } + } + + public override Builder MergeFrom(HealthCheckRequest other) { + if (other == global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance) return this; + PrepareBuilder(); + if (other.HasHost) { + Host = other.Host; + } + if (other.HasService) { + Service = other.Service; + } + this.MergeUnknownFields(other.UnknownFields); + return this; + } + + public override Builder MergeFrom(pb::ICodedInputStream input) { + return MergeFrom(input, pb::ExtensionRegistry.Empty); + } + + public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + PrepareBuilder(); + pb::UnknownFieldSet.Builder unknownFields = null; + uint tag; + string field_name; + while (input.ReadTag(out tag, out field_name)) { + if(tag == 0 && field_name != null) { + int field_ordinal = global::System.Array.BinarySearch(_healthCheckRequestFieldNames, field_name, global::System.StringComparer.Ordinal); + if(field_ordinal >= 0) + tag = _healthCheckRequestFieldTags[field_ordinal]; + else { + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + continue; + } + } + switch (tag) { + case 0: { + throw pb::InvalidProtocolBufferException.InvalidTag(); + } + default: { + if (pb::WireFormat.IsEndGroupTag(tag)) { + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + break; + } + case 10: { + result.hasHost = input.ReadString(ref result.host_); + break; + } + case 18: { + result.hasService = input.ReadString(ref result.service_); + break; + } + } + } + + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + + + public bool HasHost { + get { return result.hasHost; } + } + public string Host { + get { return result.Host; } + set { SetHost(value); } + } + public Builder SetHost(string value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + result.hasHost = true; + result.host_ = value; + return this; + } + public Builder ClearHost() { + PrepareBuilder(); + result.hasHost = false; + result.host_ = ""; + return this; + } + + public bool HasService { + get { return result.hasService; } + } + public string Service { + get { return result.Service; } + set { SetService(value); } + } + public Builder SetService(string value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + result.hasService = true; + result.service_ = value; + return this; + } + public Builder ClearService() { + PrepareBuilder(); + result.hasService = false; + result.service_ = ""; + return this; + } + } + static HealthCheckRequest() { + object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class HealthCheckResponse : pb::GeneratedMessage<HealthCheckResponse, HealthCheckResponse.Builder> { + private HealthCheckResponse() { } + private static readonly HealthCheckResponse defaultInstance = new HealthCheckResponse().MakeReadOnly(); + private static readonly string[] _healthCheckResponseFieldNames = new string[] { "status" }; + private static readonly uint[] _healthCheckResponseFieldTags = new uint[] { 8 }; + public static HealthCheckResponse DefaultInstance { + get { return defaultInstance; } + } + + public override HealthCheckResponse DefaultInstanceForType { + get { return DefaultInstance; } + } + + protected override HealthCheckResponse ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable<HealthCheckResponse, HealthCheckResponse.Builder> InternalFieldAccessors { + get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable; } + } + + #region Nested types + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public static partial class Types { + public enum ServingStatus { + UNKNOWN = 0, + SERVING = 1, + NOT_SERVING = 2, + } + + } + #endregion + + public const int StatusFieldNumber = 1; + private bool hasStatus; + private global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN; + public bool HasStatus { + get { return hasStatus; } + } + public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status { + get { return status_; } + } + + public override bool IsInitialized { + get { + return true; + } + } + + public override void WriteTo(pb::ICodedOutputStream output) { + CalcSerializedSize(); + string[] field_names = _healthCheckResponseFieldNames; + if (hasStatus) { + output.WriteEnum(1, field_names[0], (int) Status, Status); + } + UnknownFields.WriteTo(output); + } + + private int memoizedSerializedSize = -1; + public override int SerializedSize { + get { + int size = memoizedSerializedSize; + if (size != -1) return size; + return CalcSerializedSize(); + } + } + + private int CalcSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasStatus) { + size += pb::CodedOutputStream.ComputeEnumSize(1, (int) Status); + } + size += UnknownFields.SerializedSize; + memoizedSerializedSize = size; + return size; + } + public static HealthCheckResponse ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static HealthCheckResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static HealthCheckResponse ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static HealthCheckResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static HealthCheckResponse ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static HealthCheckResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input) { + return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); + } + public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); + } + public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + private HealthCheckResponse MakeReadOnly() { + return this; + } + + public static Builder CreateBuilder() { return new Builder(); } + public override Builder ToBuilder() { return CreateBuilder(this); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(HealthCheckResponse prototype) { + return new Builder(prototype); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Builder : pb::GeneratedBuilder<HealthCheckResponse, Builder> { + protected override Builder ThisBuilder { + get { return this; } + } + public Builder() { + result = DefaultInstance; + resultIsReadOnly = true; + } + internal Builder(HealthCheckResponse cloneFrom) { + result = cloneFrom; + resultIsReadOnly = true; + } + + private bool resultIsReadOnly; + private HealthCheckResponse result; + + private HealthCheckResponse PrepareBuilder() { + if (resultIsReadOnly) { + HealthCheckResponse original = result; + result = new HealthCheckResponse(); + resultIsReadOnly = false; + MergeFrom(original); + } + return result; + } + + public override bool IsInitialized { + get { return result.IsInitialized; } + } + + protected override HealthCheckResponse MessageBeingBuilt { + get { return PrepareBuilder(); } + } + + public override Builder Clear() { + result = DefaultInstance; + resultIsReadOnly = true; + return this; + } + + public override Builder Clone() { + if (resultIsReadOnly) { + return new Builder(result); + } else { + return new Builder().MergeFrom(result); + } + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.Descriptor; } + } + + public override HealthCheckResponse DefaultInstanceForType { + get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance; } + } + + public override HealthCheckResponse BuildPartial() { + if (resultIsReadOnly) { + return result; + } + resultIsReadOnly = true; + return result.MakeReadOnly(); + } + + public override Builder MergeFrom(pb::IMessage other) { + if (other is HealthCheckResponse) { + return MergeFrom((HealthCheckResponse) other); + } else { + base.MergeFrom(other); + return this; + } + } + + public override Builder MergeFrom(HealthCheckResponse other) { + if (other == global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance) return this; + PrepareBuilder(); + if (other.HasStatus) { + Status = other.Status; + } + this.MergeUnknownFields(other.UnknownFields); + return this; + } + + public override Builder MergeFrom(pb::ICodedInputStream input) { + return MergeFrom(input, pb::ExtensionRegistry.Empty); + } + + public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + PrepareBuilder(); + pb::UnknownFieldSet.Builder unknownFields = null; + uint tag; + string field_name; + while (input.ReadTag(out tag, out field_name)) { + if(tag == 0 && field_name != null) { + int field_ordinal = global::System.Array.BinarySearch(_healthCheckResponseFieldNames, field_name, global::System.StringComparer.Ordinal); + if(field_ordinal >= 0) + tag = _healthCheckResponseFieldTags[field_ordinal]; + else { + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + continue; + } + } + switch (tag) { + case 0: { + throw pb::InvalidProtocolBufferException.InvalidTag(); + } + default: { + if (pb::WireFormat.IsEndGroupTag(tag)) { + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + break; + } + case 8: { + object unknown; + if(input.ReadEnum(ref result.status_, out unknown)) { + result.hasStatus = true; + } else if(unknown is int) { + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + unknownFields.MergeVarintField(1, (ulong)(int)unknown); + } + break; + } + } + } + + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + + + public bool HasStatus { + get { return result.hasStatus; } + } + public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status { + get { return result.Status; } + set { SetStatus(value); } + } + public Builder SetStatus(global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus value) { + PrepareBuilder(); + result.hasStatus = true; + result.status_ = value; + return this; + } + public Builder ClearStatus() { + PrepareBuilder(); + result.hasStatus = false; + result.status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN; + return this; + } + } + static HealthCheckResponse() { + object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null); + } + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs new file mode 100644 index 0000000000..ed9fc4ed77 --- /dev/null +++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs @@ -0,0 +1,78 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: health.proto +#region Designer generated code + +using System; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; + +namespace Grpc.Health.V1Alpha { + public static class Health + { + static readonly string __ServiceName = "grpc.health.v1alpha.Health"; + + static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckRequest> __Marshaller_HealthCheckRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckRequest.ParseFrom); + static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckResponse> __Marshaller_HealthCheckResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckResponse.ParseFrom); + + static readonly Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse> __Method_Check = new Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse>( + MethodType.Unary, + "Check", + __Marshaller_HealthCheckRequest, + __Marshaller_HealthCheckResponse); + + // client-side stub interface + public interface IHealthClient + { + global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken)); + Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken)); + } + + // server-side interface + public interface IHealth + { + Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> Check(ServerCallContext context, global::Grpc.Health.V1Alpha.HealthCheckRequest request); + } + + // client stub + public class HealthClient : AbstractStub<HealthClient, StubConfiguration>, IHealthClient + { + public HealthClient(Channel channel) : this(channel, StubConfiguration.Default) + { + } + public HealthClient(Channel channel, StubConfiguration config) : base(channel, config) + { + } + public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken)) + { + var call = CreateCall(__ServiceName, __Method_Check); + return Calls.BlockingUnaryCall(call, request, token); + } + public Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken)) + { + var call = CreateCall(__ServiceName, __Method_Check); + return Calls.AsyncUnaryCall(call, request, token); + } + } + + // creates service definition that can be registered with a server + public static ServerServiceDefinition BindService(IHealth serviceImpl) + { + return ServerServiceDefinition.CreateBuilder(__ServiceName) + .AddMethod(__Method_Check, serviceImpl.Check).Build(); + } + + // creates a new client stub + public static IHealthClient NewStub(Channel channel) + { + return new HealthClient(channel); + } + + // creates a new client stub + public static IHealthClient NewStub(Channel channel, StubConfiguration config) + { + return new HealthClient(channel, config); + } + } +} +#endregion diff --git a/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs new file mode 100644 index 0000000000..db3a2a0942 --- /dev/null +++ b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs @@ -0,0 +1,132 @@ +#region Copyright notice and license +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Grpc.Core; +using Grpc.Core.Utils; +using Grpc.Health.V1Alpha; + +namespace Grpc.HealthCheck +{ + /// <summary> + /// Implementation of a simple Health service. Useful for health checking. + /// + /// Registering service with a server: + /// <code> + /// var serviceImpl = new HealthServiceImpl(); + /// server = new Server(); + /// server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl)); + /// </code> + /// </summary> + public class HealthServiceImpl : Grpc.Health.V1Alpha.Health.IHealth + { + private readonly object myLock = new object(); + private readonly Dictionary<Key, HealthCheckResponse.Types.ServingStatus> statusMap = + new Dictionary<Key, HealthCheckResponse.Types.ServingStatus>(); + + /// <summary> + /// Sets the health status for given host and service. + /// </summary> + /// <param name="host">The host. Cannot be null.</param> + /// <param name="service">The service. Cannot be null.</param> + /// <param name="status">the health status</param> + public void SetStatus(string host, string service, HealthCheckResponse.Types.ServingStatus status) + { + lock (myLock) + { + statusMap[CreateKey(host, service)] = status; + } + } + + /// <summary> + /// Clears health status for given host and service. + /// </summary> + /// <param name="host">The host. Cannot be null.</param> + /// <param name="service">The service. Cannot be null.</param> + public void ClearStatus(string host, string service) + { + lock (myLock) + { + statusMap.Remove(CreateKey(host, service)); + } + } + + /// <summary> + /// Clears statuses for all hosts and services. + /// </summary> + public void ClearAll() + { + lock (myLock) + { + statusMap.Clear(); + } + } + + public Task<HealthCheckResponse> Check(ServerCallContext context, HealthCheckRequest request) + { + lock (myLock) + { + var host = request.HasHost ? request.Host : ""; + var service = request.HasService ? request.Service : ""; + + HealthCheckResponse.Types.ServingStatus status; + if (!statusMap.TryGetValue(CreateKey(host, service), out status)) + { + // TODO(jtattermusch): returning specific status from server handler is not supported yet. + throw new RpcException(new Status(StatusCode.NotFound, "")); + } + return Task.FromResult(HealthCheckResponse.CreateBuilder().SetStatus(status).Build()); + } + } + + private static Key CreateKey(string host, string service) + { + return new Key(host, service); + } + + private struct Key + { + public Key(string host, string service) + { + this.Host = Preconditions.CheckNotNull(host); + this.Service = Preconditions.CheckNotNull(service); + } + + readonly string Host; + readonly string Service; + } + } +} diff --git a/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs b/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..6cfdb7e6e2 --- /dev/null +++ b/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs @@ -0,0 +1,12 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +[assembly: AssemblyTitle("Grpc.HealthCheck")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Google Inc. All rights reserved.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: AssemblyVersion("0.6.*")]
\ No newline at end of file diff --git a/src/csharp/Grpc.HealthCheck/packages.config b/src/csharp/Grpc.HealthCheck/packages.config new file mode 100644 index 0000000000..094a30981e --- /dev/null +++ b/src/csharp/Grpc.HealthCheck/packages.config @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Google.ProtocolBuffers" version="2.4.1.555" targetFramework="net45" /> + <package id="Ix-Async" version="1.2.3" targetFramework="net45" /> +</packages>
\ No newline at end of file diff --git a/src/csharp/Grpc.HealthCheck/proto/health.proto b/src/csharp/Grpc.HealthCheck/proto/health.proto new file mode 100644 index 0000000000..08df7e104e --- /dev/null +++ b/src/csharp/Grpc.HealthCheck/proto/health.proto @@ -0,0 +1,52 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// TODO(jtattermusch): switch to proto3 once C# supports that. +syntax = "proto2"; + +package grpc.health.v1alpha; +option csharp_namespace = "Grpc.Health.V1Alpha"; + +message HealthCheckRequest { + optional string host = 1; + optional string service = 2; +} + +message HealthCheckResponse { + enum ServingStatus { + UNKNOWN = 0; + SERVING = 1; + NOT_SERVING = 2; + } + optional ServingStatus status = 1; +} + +service Health { + rpc Check(HealthCheckRequest) returns (HealthCheckResponse); +}
\ No newline at end of file |