是否可以指示 ServicePartitionClient 与服务结构中的特定节点对话?

Is it possible to instruct ServicePartitionClient to talk to a specific node in service fabric?

我有

public class HttpCommunicationClient : HttpClient, ICommunicationClient
{
    public HttpCommunicationClient()
        : base(new HttpClientHandler() { AllowAutoRedirect = false, UseCookies = false })
    {
    }

    public HttpCommunicationClient(HttpMessageHandler handler)
        : base(handler)
    {
    }

    public HttpCommunicationClient(HttpMessageHandler handler, bool disposeHandler)
        : base(handler, disposeHandler)
    {
    }

    #region ICommunicationClient

    string ICommunicationClient.ListenerName { get; set; }

    ResolvedServiceEndpoint ICommunicationClient.Endpoint { get; set; }

    ResolvedServicePartition ICommunicationClient.ResolvedServicePartition { get; set; }

    #endregion ICommunicationClient
}

public class HttpCommunicationClientFactory : CommunicationClientFactoryBase<HttpCommunicationClient>
{
    private readonly Func<HttpCommunicationClient> _innerDispatcherProvider;

    public HttpCommunicationClientFactory(IServicePartitionResolver servicePartitionResolver = null, IEnumerable<IExceptionHandler> exceptionHandlers = null, string traceId = null)
        : this(() => new HttpCommunicationClient(), servicePartitionResolver, exceptionHandlers, traceId)
    {
    }

    public HttpCommunicationClientFactory(Func<HttpCommunicationClient> innerDispatcherProvider, IServicePartitionResolver servicePartitionResolver = null, IEnumerable<IExceptionHandler> exceptionHandlers = null, string traceId = null)
        : base(servicePartitionResolver, exceptionHandlers, traceId)
    {
        if (innerDispatcherProvider == null)
        {
            throw new ArgumentNullException(nameof(innerDispatcherProvider));
        }

        _innerDispatcherProvider = innerDispatcherProvider;
    }

    protected override void AbortClient(HttpCommunicationClient dispatcher)
    {
        if (dispatcher != null)
        {
            dispatcher.Dispose();
        }
    }

    protected override Task<HttpCommunicationClient> CreateClientAsync(string endpoint, CancellationToken cancellationToken)
    {
        var dispatcher = _innerDispatcherProvider.Invoke();
        dispatcher.BaseAddress = new Uri(endpoint, UriKind.Absolute);

        return Task.FromResult(dispatcher);
    }

    protected override bool ValidateClient(HttpCommunicationClient dispatcher)
    {
        return dispatcher != null && dispatcher.BaseAddress != null;
    }

    protected override bool ValidateClient(string endpoint, HttpCommunicationClient dispatcher)
    {
        return dispatcher != null && dispatcher.BaseAddress == new Uri(endpoint, UriKind.Absolute);
    }
} 

并像下面这样使用它

var servicePartitionClient = new ServicePartitionClient<HttpCommunicationClient>(_httpClientFactory,
                                                                                           _options.ServiceUri,
                                                                                           _options.GetServicePartitionKey?.Invoke(context),
                                                                                           _options.TargetReplicaSelector,
                                                                                           _options.ListenerName,
                                                                                           _options.OperationRetrySettings);

using (var responseMessage = await servicePartitionClient.InvokeWithRetryAsync(httpClient => ExecuteServiceCallAsync(httpClient, context)))
{
    await responseMessage.CopyToCurrentContext(context);
}

现在的问题是,如果我在使用 ServicePartitionClient 时知道我希望它连接到特定节点,有什么办法可以做到吗?

情况是它是一个将请求转发到其他服务的网关应用程序,我希望它的行为类似于粘性会话。

我找到了一个解决方案,我在下面的 ExecuteServiceCallAsync 调用中从请求中读取一个 cookie,其中包含关于它连接到哪个节点的信息,如果它是一个粘性会话,如果不存在 cookie,我设置一个来自请求的信息。如果该节点不再存在,则将 cookie 更新为新节点。

using (var responseMessage = await servicePartitionClient.InvokeWithRetryAsync(httpClient => ExecuteServiceCallAsync(httpClient, context)))
{
    await responseMessage.CopyToCurrentContext(context);
}

从服务的角度思考比节点更有意义。因此,您不是连接到特定节点,而是实际连接到服务的特定实例。

当您连接到一个服务时,如果它是无状态的,那么根据它是无状态的定义,您连接到哪个实例并不重要。如果您发现用户绑定到服务的特定实例,则该服务是有状态的(它会跟踪某些用户状态),而这正是 有状态服务 的场景类型是为了处理。