Service-Fabric 绑定到多个端点

Posted

技术标签:

【中文标题】Service-Fabric 绑定到多个端点【英文标题】:Service-Fabric bind to multiple endpoints 【发布时间】:2017-06-23 16:32:35 【问题描述】:

是否可以绑定服务结构应用以侦听多个端口?

基本上,我正在尝试建立一个面向公众的服务,它监听 http:80 和 https:443,并将任何 http 请求重定向到 https。

我创建了一个新的 ASP.net Core 服务,它单独运行良好。 IE。使用 SSL 443 或仅使用非 SSL 80,但是当我同时添加 ServiceInstanceListeners 时,它就失败了!

Service Fabric Explorer 多次超时后提示以下错误:

Unhealthy event: SourceId='System.RA', Property='ReplicaOpenStatus', HealthState='Warning', ConsiderWarningAsError=false.
Replica had multiple failures in API call: IStatelessServiceInstance.Open(); Error = System.Fabric.FabricElementAlreadyExistsException (-2146233088)
Unique Name must be specified for each listener when multiple communication listeners are used
   at Microsoft.ServiceFabric.Services.Communication.ServiceEndpointCollection.AddEndpointCallerHoldsLock(String listenerName, String endpointAddress)
   at Microsoft.ServiceFabric.Services.Communication.ServiceEndpointCollection.AddEndpoint(String listenerName, String endpointAddress)
   at Microsoft.ServiceFabric.Services.Runtime.StatelessServiceInstanceAdapter.d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.ServiceFabric.Services.Runtime.StatelessServiceInstanceAdapter.d__0.MoveNext()

这很奇怪,因为两个听众的名字不同——看起来是这样。我应该在某个地方设置我错过的侦听器名称吗?

我为此使用了 Asp.net Core 模板。我的无状态服务代码如下:

internal sealed class Web : StatelessService

    public Web(StatelessServiceContext context)
        : base(context)
     

    /// <summary>
    /// Optional override to create listeners (like tcp, http) for this service instance.
    /// </summary>
    /// <returns>The collection of listeners.</returns>
    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    
        return new ServiceInstanceListener[]
        
            new ServiceInstanceListener(serviceContext =>
                new WebListenerCommunicationListener(serviceContext, "ServiceEndpointHttps", url =>
                
                    ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting WebListener on url");

                    return new WebHostBuilder()
                                .UseWebListener()
                                .ConfigureServices(
                                    services => services
                                        .AddSingleton<StatelessServiceContext>(serviceContext))
                                .UseContentRoot(Directory.GetCurrentDirectory())
                                .UseStartup<Startup>()
                                .UseUrls(url)
                                .Build();
                )),


            new ServiceInstanceListener(serviceContext =>
                new WebListenerCommunicationListener(serviceContext, "ServiceEndpointHttp", url =>
                
                    ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting WebListener on url");

                    return new WebHostBuilder()
                                .UseWebListener()
                                .ConfigureServices(
                                    services => services
                                        .AddSingleton<StatelessServiceContext>(serviceContext))
                                .UseContentRoot(Directory.GetCurrentDirectory())
                                .UseStartup<Startup>()
                                .UseUrls(url)
                                .Build();
                ))
        ;
    

【问题讨论】:

【参考方案1】:

我需要在具有构造函数的ServiceInstanceListener 上设置名称

public ServiceInstanceListener(Func<StatelessServiceContext, ICommunicationListener> createCommunicationListener, string name = "");

我没有意识到它有额外的参数:)

【讨论】:

名称应与服务设置中的端点名称相匹配。对于具有单个端点类型的服务,可以将其留空,但一旦您有多个端点,您需要通过名称来识别它们。 节省了一天! @yoape 这是否意味着 servicemanifest.xml 中端点中的“名称”属性?【参考方案2】:

您可以使用下面的代码自动执行所有这些操作,并在需要的地方记录所需的信息。

var currentEndpoint = "";
try

  IList<ServiceInstanceListener> listeners = new List<ServiceInstanceListener>();
  var endpoints = FabricRuntime.GetActivationContext().GetEndpoints();

  foreach (var endpoint in endpoints)
  
    currentEndpoint = endpoint.Name;
    logger.LogInformation("Website trying to LISTEN : " + currentEndpoint);

    var webListner = new ServiceInstanceListener(serviceContext =>
       new WebListenerCommunicationListener(serviceContext, endpoint.Name, (url, listener) =>
       
         url = endpoint.Protocol + "://+:" + endpoint.Port;
         logger.LogInformation("Website Listening : " + currentEndpoint);
         return new WebHostBuilder().UseWebListener()       .UseContentRoot(Directory.GetCurrentDirectory())
              .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
              .UseStartup<Startup>()
              .UseUrls(url)
              .Build();
       ), endpoint.Name.ToString());
    listeners.Add(webListner);
  
  return listeners;

catch (Exception ex)

  logger.LogError("Exception occured while listening endpoint: " + currentEndpoint, ex);
  throw;

【讨论】:

fwiw,看起来“url”实际上已经设置为endpoint.Protocol + "://+:" + endpoint.Port;,所以我最终不必做那部分。感谢您的详细回答!

以上是关于Service-Fabric 绑定到多个端点的主要内容,如果未能解决你的问题,请参考以下文章

Azure Service Fabric 群集端点不可访问

基于 IIS 绑定将 WCF 端点动态绑定到 HTTPS

Gunicorn 多个烧瓶工人和绑定任务 celery

WCF 多端点

将对象绑定到 Web API 端点时指定自定义属性名称

从 http 到 https,得到“找不到与绑定 WebHttpBinding 的端点的方案 http 匹配的基地址”