Commit 59f90b07 authored by Savorboard's avatar Savorboard

Add Nodediscovry

parent 1d67da71
// Copyright (c) .NET Core Community. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
namespace DotNetCore.CAP.Dashboard.NodeDiscovery
{
public class DiscoveryOptions
{
public const string DefaultDiscoveryServerHost = "localhost";
public const int DefaultDiscoveryServerPort = 8500;
public const string DefaultCurrentNodeHostName = "localhost";
public const int DefaultCurrentNodePort = 5000;
public const string DefaultMatchPath = "/cap";
public DiscoveryOptions()
{
DiscoveryServerHostName = DefaultDiscoveryServerHost;
DiscoveryServerPort = DefaultDiscoveryServerPort;
CurrentNodeHostName = DefaultCurrentNodeHostName;
CurrentNodePort = DefaultCurrentNodePort;
MatchPath = DefaultMatchPath;
}
public string DiscoveryServerHostName { get; set; }
public int DiscoveryServerPort { get; set; }
public string CurrentNodeHostName { get; set; }
public int CurrentNodePort { get; set; }
public string NodeId { get; set; }
public string NodeName { get; set; }
public string MatchPath { get; set; }
}
}
\ No newline at end of file
// Copyright (c) .NET Core Community. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using System;
using DotNetCore.CAP;
using Microsoft.Extensions.DependencyInjection;
namespace DotNetCore.CAP.Dashboard.NodeDiscovery
{
internal sealed class DiscoveryOptionsExtension : ICapOptionsExtension
{
private readonly Action<DiscoveryOptions> _options;
public DiscoveryOptionsExtension(Action<DiscoveryOptions> option)
{
_options = option;
}
public void AddServices(IServiceCollection services)
{
var discoveryOptions = new DiscoveryOptions();
_options?.Invoke(discoveryOptions);
services.AddSingleton(discoveryOptions);
services.AddSingleton<IDiscoveryProviderFactory, DiscoveryProviderFactory>();
services.AddSingleton<IProcessingServer, ConsulProcessingNodeServer>();
services.AddSingleton(x =>
{
var configOptions = x.GetService<DiscoveryOptions>();
var factory = x.GetService<IDiscoveryProviderFactory>();
return factory.Create(configOptions);
});
}
}
public static class CapDiscoveryOptionsExtensions
{
public static CapOptions UseDiscovery(this CapOptions capOptions)
{
return capOptions.UseDiscovery(opt => { });
}
public static CapOptions UseDiscovery(this CapOptions capOptions, Action<DiscoveryOptions> options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
capOptions.RegisterExtension(new DiscoveryOptionsExtension(options));
return capOptions;
}
}
}
\ No newline at end of file
// Copyright (c) .NET Core Community. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using System;
using Microsoft.Extensions.Logging;
namespace DotNetCore.CAP.Dashboard.NodeDiscovery
{
internal class DiscoveryProviderFactory : IDiscoveryProviderFactory
{
private readonly ILoggerFactory _loggerFactory;
public DiscoveryProviderFactory(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
}
public INodeDiscoveryProvider Create(DiscoveryOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return new ConsulNodeDiscoveryProvider(_loggerFactory, options);
}
}
}
\ No newline at end of file
// Copyright (c) .NET Core Community. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
namespace DotNetCore.CAP.Dashboard.NodeDiscovery
{
internal interface IDiscoveryProviderFactory
{
INodeDiscoveryProvider Create(DiscoveryOptions options);
}
}
\ No newline at end of file
// Copyright (c) .NET Core Community. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Consul;
using Microsoft.Extensions.Logging;
namespace DotNetCore.CAP.Dashboard.NodeDiscovery
{
public class ConsulNodeDiscoveryProvider : INodeDiscoveryProvider, IDisposable
{
private readonly ILogger<ConsulNodeDiscoveryProvider> _logger;
private readonly DiscoveryOptions _options;
private ConsulClient _consul;
public ConsulNodeDiscoveryProvider(ILoggerFactory logger, DiscoveryOptions options)
{
_logger = logger.CreateLogger<ConsulNodeDiscoveryProvider>();
_options = options;
InitClient();
}
public void Dispose()
{
_consul.Dispose();
}
public async Task<IList<Node>> GetNodes()
{
try
{
var nodes = new List<Node>();
var services = await _consul.Catalog.Services();
foreach (var service in services.Response)
{
var serviceInfo = await _consul.Catalog.Service(service.Key);
var node = serviceInfo.Response.SkipWhile(x => !x.ServiceTags.Contains("CAP"))
.Select(info => new Node
{
Id = info.ServiceID,
Name = info.ServiceName,
Address = info.ServiceAddress,
Port = info.ServicePort,
Tags = string.Join(", ", info.ServiceTags)
}).ToList();
nodes.AddRange(node);
}
CapCache.Global.AddOrUpdate("cap.nodes.count", nodes.Count, TimeSpan.FromSeconds(60), true);
return nodes;
}
catch (Exception ex)
{
CapCache.Global.AddOrUpdate("cap.nodes.count", 0, TimeSpan.FromSeconds(20));
_logger.LogError(
$"Get consul nodes raised an exception. Exception:{ex.Message},{ex.InnerException.Message}");
return null;
}
}
public Task RegisterNode()
{
try
{
return _consul.Agent.ServiceRegister(new AgentServiceRegistration
{
ID = _options.NodeId,
Name = _options.NodeName,
Address = _options.CurrentNodeHostName,
Port = _options.CurrentNodePort,
Tags = new[] {"CAP", "Client", "Dashboard"},
Check = new AgentServiceCheck
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(30),
Interval = TimeSpan.FromSeconds(10),
Status = HealthStatus.Passing,
HTTP =
$"http://{_options.CurrentNodeHostName}:{_options.CurrentNodePort}{_options.MatchPath}/health"
}
});
}
catch (Exception ex)
{
_logger.LogError(
$"Get consul nodes raised an exception. Exception:{ex.Message},{ex.InnerException.Message}");
return null;
}
}
private void InitClient()
{
_consul = new ConsulClient(config =>
{
config.WaitTime = TimeSpan.FromSeconds(5);
config.Address = new Uri($"http://{_options.DiscoveryServerHostName}:{_options.DiscoveryServerPort}");
});
}
}
}
\ No newline at end of file
// Copyright (c) .NET Core Community. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading.Tasks;
namespace DotNetCore.CAP.Dashboard.NodeDiscovery
{
public interface INodeDiscoveryProvider
{
Task<IList<Node>> GetNodes();
Task RegisterNode();
}
}
\ No newline at end of file
// Copyright (c) .NET Core Community. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
namespace DotNetCore.CAP.Dashboard.NodeDiscovery
{
internal class ConsulProcessingNodeServer : IProcessingServer
{
private readonly DiscoveryOptions _dashboardOptions;
private readonly IDiscoveryProviderFactory _discoveryProviderFactory;
public ConsulProcessingNodeServer(
DiscoveryOptions dashboardOptions,
IDiscoveryProviderFactory discoveryProviderFactory)
{
_dashboardOptions = dashboardOptions;
_discoveryProviderFactory = discoveryProviderFactory;
}
public void Start()
{
var discoveryProvider = _discoveryProviderFactory.Create(_dashboardOptions);
discoveryProvider.RegisterNode();
}
public void Pulse()
{
//ignore
}
public void Dispose()
{
}
}
}
\ No newline at end of file
// Copyright (c) .NET Core Community. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
namespace DotNetCore.CAP.Dashboard.NodeDiscovery
{
public class Node
{
public string Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int Port { get; set; }
public string Tags { get; set; }
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment