2017-02-06 5 views
7

Можно ли связать приложение рабочей ткани для прослушивания нескольких портов?Service-Fabric связывается с несколькими конечными точками

В основном я пытаюсь открыть службу общего доступа, которая прослушивает http: 80 и https: 443 и перенаправляет любые HTTP-запросы на https.

Я создал новый сервис ASP.net Core, он отлично работает индивидуально. То есть с SSL 443 или просто не SSL 80, но когда я добавляю и ServiceInstanceListeners, он просто терпит неудачу!

Service Fabric Исследователь говорит следующее сообщение об ошибке после тайм-аута несколько раз:

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 для этого. Мой код Stateless службы выглядит следующим образом:

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(); 
       })) 
     }; 
    } 
} 

ответ

6

мне нужно установить имя на ServiceInstanceListener, который имеет конструктор

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

я не понял, что имел дополнительный Params :)

+1

Имя должно совпадать с именем конечной точки в настройках службы. Для службы с одной конечной точкой типа это нормально оставить ее пустой, но как только у вас есть несколько, вам нужно идентифицировать их по имени. – yoape

+1

Полезно знать, спасибо! В будущем я не буду меня трогать. – Mardoxx

1

You может автоматизировать все это, используя приведенный ниже код, а также записывать необходимую информацию там, где это необходимо.

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; 
} 
+0

fwiw, похоже, что «url» на самом деле установлен в 'endpoint.Protocol +": // +: "+ endpoint.Port;' уже, поэтому мне не пришлось делать эту часть. Спасибо за подробный ответ! – JohnnyFun