Повторное использование соединений в Azure Relay Bus

Мы рассматриваем возможность подключения веб-сайтов Azure к локальным службам WCF. Мы хотим использовать для этого Azure Relay Bus.

Первоначальная настройка канала TCP требует затрат, в нашем случае около 3 секунд. Это понятно. Мы кешируем канал, поэтому следующий вызов идет быстрее. ( 250 мс) Канал кэшируется в хранилище ThreadLocal.

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

Мой вопрос:

Как мы можем предотвратить, чтобы реальный пользователь столкнулся с задержкой настройки канала? Это нормальная практика иметь канал TCP для каждого потока клиента?

Примечание. Локально мы используем службы автозапуска IIS или NT для "разогрева" наших служб WCF, но так ли это для веб-сайта, работающего в Azure? Тот факт, что каждый поток имеет свой собственный канал, не облегчает его.

Код показан ниже.

public static class NetTcpRelayClient<TChannel>
{
    /// <summary>
    /// A ThreadLocal instance of the channel, so that each thread can have an open TCP channel
    /// </summary>
    private static ThreadLocal<TChannel> staticChannel = new ThreadLocal<TChannel>();

    /// <summary>
    /// A shared instance of the ChannelFactory
    /// </summary>
    private static ChannelFactory<TChannel> cf = null;

    /// <summary>
    /// Creates the channel.
    /// </summary>
    /// <returns>The created channel</returns>
    private static TChannel CreateChannel()
    {
        // get the url and access parameters from the configuration service
        var address = ServiceSecurityInspector.GetNetTcpRelayBindingAddress(typeof(TContract));
        string issuerName = ConfigurationManager.AppSettings["Shared.appsettings.AzureServiceBus.IssuerName"];
        string issuerSecret = ConfigurationManager.AppSettings["Shared.appsettings.AzureServiceBus.IssuerSecret"];

        // create a NetTcpRelayBinding, 
        if (cf == null)
        {
            cf = new ChannelFactory<TChannel>(new NetTcpRelayBinding(), new EndpointAddress(address));

            cf.Endpoint.Behaviors.Add(new TransportClientEndpointBehavior
            {
                TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerSecret)
            });
        }

        TChannel channel = cf.CreateChannel();

        // open the channel
        IClientChannel clientChannel = channel as IClientChannel;
        if (clientChannel != null)
        {
            clientChannel.Open();
        }

        return channel;
    }

    /// <summary>
    /// Gets the channel for making a call over the relay bus.
    /// Note that the channel is cached.
    /// And that each thread has it's own channnel.
    /// </summary>
    /// <returns>The channel</returns>
    public static TChannel GetChannel()
    {
        // check if we have a channel instance already
        if (!staticChannel.IsValueCreated)
        {
            // no, create one
            staticChannel.Value = CreateChannel();
        }
        else
        {
            // if the channel exists already
            IClientChannel clientChannel = staticChannel as IClientChannel;

            // check if it is open, if not, make a new one
            if (clientChannel != null)
            {
                CommunicationState state = clientChannel.State;

                // check its state
                if (state == CommunicationState.Faulted)
                {
                    // channel is in faulted state, close and recreate it
                    CloseChannel();

                    staticChannel.Value = CreateChannel();
                }
                else if ((state == CommunicationState.Closed) || (state == CommunicationState.Closing))
                {
                    // channel is closed or closing, recreate it
                    staticChannel.Value = CreateChannel();
                }
            }
        }

        return staticChannel.Value;
    }

    /// <summary>
    /// Closes the channel in a proper way
    /// </summary>
    private static void CloseChannel()
    {
        // always check if we still have a valid channel
        if (staticChannel != null)
        {
            IClientChannel clientChannel = staticChannel as IClientChannel;
            if (clientChannel != null)
            {
                // if the channel is open, we close it
                if (clientChannel.State != CommunicationState.Closed)
                {
                    clientChannel.Abort();
                }
            }

            // and we set the static variable back to it's default ( = null )
            staticChannel = null;
        }
    }
}

0 ответов

Другие вопросы по тегам