private static CosmosHttpClient CreateHelper(
            HttpClient httpClient,
            HttpMessageHandler httpMessageHandler,
            TimeSpan requestTimeout,
            UserAgentContainer userAgentContainer,
            ApiType apiType,
            ICommunicationEventSource eventSource)
        {
            if (httpClient == null)
            {
                throw new ArgumentNullException(nameof(httpClient));
            }

            httpClient.Timeout = requestTimeout > CosmosHttpClientCore.GatewayRequestTimeout
                ? requestTimeout
                : CosmosHttpClientCore.GatewayRequestTimeout;
            httpClient.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue {
                NoCache = true
            };

            httpClient.AddUserAgentHeader(userAgentContainer);
            httpClient.AddApiTypeHeader(apiType);

            // Set requested API version header that can be used for
            // version enforcement.
            httpClient.DefaultRequestHeaders.Add(HttpConstants.HttpHeaders.Version,
                                                 HttpConstants.Versions.CurrentVersion);

            httpClient.DefaultRequestHeaders.Add(HttpConstants.HttpHeaders.Accept, RuntimeConstants.MediaTypes.Json);

            return(new CosmosHttpClientCore(
                       httpClient,
                       httpMessageHandler,
                       eventSource));
        }
        public static CosmosHttpClient CreateWithConnectionPolicy(
            ApiType apiType,
            ICommunicationEventSource eventSource,
            ConnectionPolicy connectionPolicy,
            HttpMessageHandler httpMessageHandler,
            EventHandler <SendingRequestEventArgs> sendingRequestEventArgs,
            EventHandler <ReceivedResponseEventArgs> receivedResponseEventArgs)
        {
            if (connectionPolicy == null)
            {
                throw new ArgumentNullException(nameof(connectionPolicy));
            }

            Func <HttpClient> httpClientFactory = connectionPolicy.HttpClientFactory;

            if (httpClientFactory != null)
            {
                if (sendingRequestEventArgs != null &&
                    receivedResponseEventArgs != null)
                {
                    throw new InvalidOperationException($"{nameof(connectionPolicy.HttpClientFactory)} can not be set at the same time as {nameof(sendingRequestEventArgs)} or {nameof(ReceivedResponseEventArgs)}");
                }

                HttpClient userHttpClient = httpClientFactory.Invoke() ?? throw new ArgumentNullException($"{nameof(httpClientFactory)} returned null. {nameof(httpClientFactory)} must return a HttpClient instance.");
                return(CosmosHttpClientCore.CreateHelper(
                           httpClient: userHttpClient,
                           httpMessageHandler: httpMessageHandler,
                           requestTimeout: connectionPolicy.RequestTimeout,
                           userAgentContainer: connectionPolicy.UserAgentContainer,
                           apiType: apiType,
                           eventSource: eventSource));
            }

            if (httpMessageHandler == null)
            {
                httpMessageHandler = CosmosHttpClientCore.CreateHttpClientHandler(
                    gatewayModeMaxConnectionLimit: connectionPolicy.MaxConnectionLimit,
                    webProxy: null);
            }

            if (sendingRequestEventArgs != null ||
                receivedResponseEventArgs != null)
            {
                httpMessageHandler = CosmosHttpClientCore.CreateHttpMessageHandler(
                    httpMessageHandler,
                    sendingRequestEventArgs,
                    receivedResponseEventArgs);
            }

            HttpClient httpClient = new HttpClient(httpMessageHandler);

            return(CosmosHttpClientCore.CreateHelper(
                       httpClient: httpClient,
                       httpMessageHandler: httpMessageHandler,
                       requestTimeout: connectionPolicy.RequestTimeout,
                       userAgentContainer: connectionPolicy.UserAgentContainer,
                       apiType: apiType,
                       eventSource: eventSource));
        }
 private CosmosHttpClientCore(
     HttpClient httpClient,
     HttpMessageHandler httpMessageHandler,
     ICommunicationEventSource eventSource)
 {
     this.httpClient         = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
     this.eventSource        = eventSource ?? throw new ArgumentNullException(nameof(eventSource));
     this.HttpMessageHandler = httpMessageHandler;
 }
 public GatewayStoreClient(
     CosmosHttpClient httpClient,
     ICommunicationEventSource eventSource,
     JsonSerializerSettings serializerSettings = null)
 {
     this.httpClient         = httpClient;
     this.SerializerSettings = serializerSettings;
     this.eventSource        = eventSource;
 }
Пример #5
0
        public StoreClientFactory(
            Protocol protocol,
            int requestTimeoutInSeconds,
            int maxConcurrentConnectionOpenRequests,
            UserAgentContainer userAgent          = null,                                 // optional for both HTTPS and RNTBD
            ICommunicationEventSource eventSource = null,                                 // required for HTTPS, not used for RNTBD
            string overrideHostNameInCertificate  = null,                                 // optional for RNTBD, not used for HTTPS
            int openTimeoutInSeconds          = 0,                                        // optional for RNTBD, not used for HTTPS
            int idleTimeoutInSeconds          = 1800,                                     // optional for both HTTPS and RNTBD
            int timerPoolGranularityInSeconds = 0,                                        // optional for RNTBD, not used for HTTPS
            int maxRntbdChannels                = ushort.MaxValue,                        // RNTBD
            int rntbdPartitionCount             = 1,                                      // RNTBD
            int maxRequestsPerRntbdChannel      = 30,                                     // RNTBD
            int receiveHangDetectionTimeSeconds = 65,                                     // RNTBD
            int sendHangDetectionTimeSeconds    = 10,                                     // RNTBD
            Func <TransportClient, TransportClient> transportClientHandlerFactory = null, // Interceptor factory
            bool enableCpuMonitor = true)
        {
            // <=0 means idle timeout is disabled.
            // valid value: >= 10 minutes
            if (idleTimeoutInSeconds > 0 && idleTimeoutInSeconds < 600)
            {
                throw new ArgumentOutOfRangeException(nameof(idleTimeoutInSeconds));
            }

            if (protocol == Protocol.Https)
            {
                if (eventSource == null)
                {
                    throw new ArgumentOutOfRangeException("eventSource");
                }
                this.transportClient = new HttpTransportClient(requestTimeoutInSeconds, eventSource, userAgent, idleTimeoutInSeconds);
            }
            else if (protocol == Protocol.Tcp)
            {
                if (maxRntbdChannels <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(maxRntbdChannels));
                }
                if ((rntbdPartitionCount < 1) || (rntbdPartitionCount > 8))
                {
                    throw new ArgumentOutOfRangeException(nameof(rntbdPartitionCount));
                }
                if (maxRequestsPerRntbdChannel <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(maxRequestsPerRntbdChannel));
                }
                if (maxRntbdChannels > ushort.MaxValue)
                {
                    DefaultTrace.TraceWarning(
                        "The value of {0} is unreasonably large. Received: {1}. " +
                        "Use {2} to represent \"effectively infinite\".",
                        nameof(maxRntbdChannels),
                        maxRntbdChannels,
                        ushort.MaxValue);
                }
                const int minRecommendedMaxRequestsPerChannel = 10;
                const int maxRecommendedMaxRequestsPerChannel = 10000;
                if (maxRequestsPerRntbdChannel < minRecommendedMaxRequestsPerChannel)
                {
                    DefaultTrace.TraceWarning(
                        "The value of {0} is unreasonably small. Received: {1}. " +
                        "Small values of {0} can cause a large number of RNTBD " +
                        "channels to be opened to the same back-end. Reasonable " +
                        "values are between {2} and {3}",
                        nameof(maxRequestsPerRntbdChannel),
                        maxRequestsPerRntbdChannel,
                        minRecommendedMaxRequestsPerChannel,
                        maxRecommendedMaxRequestsPerChannel);
                }
                if (maxRequestsPerRntbdChannel > maxRecommendedMaxRequestsPerChannel)
                {
                    DefaultTrace.TraceWarning(
                        "The value of {0} is unreasonably large. Received: {1}. " +
                        "Large values of {0} can cause significant head-of-line " +
                        "blocking over RNTBD channels. Reasonable values are between {2} and {3}",
                        nameof(maxRequestsPerRntbdChannel),
                        maxRequestsPerRntbdChannel,
                        minRecommendedMaxRequestsPerChannel,
                        maxRecommendedMaxRequestsPerChannel);
                }
                // Not related to maxRecommendedMaxRequestsPerChannel.
                const int minRequiredSimultaneousRequests = 10000;
                if (checked (maxRntbdChannels * maxRequestsPerRntbdChannel) <
                    minRequiredSimultaneousRequests)
                {
                    DefaultTrace.TraceCritical(
                        "The number of simultaneous requests allowed per backend " +
                        "is unreasonably small. Received {0} = {1}, {2} = {3}. " +
                        "Reasonable values are at least {4}",
                        nameof(maxRntbdChannels), maxRntbdChannels,
                        nameof(maxRequestsPerRntbdChannel), maxRequestsPerRntbdChannel,
                        minRequiredSimultaneousRequests);
                }
                const int minReceiveHangDetectionTimeSeconds = 65;
                const int maxReceiveHangDetectionTimeSeconds = 180;
                if (receiveHangDetectionTimeSeconds < minReceiveHangDetectionTimeSeconds)
                {
                    DefaultTrace.TraceWarning(
                        "The value of {0} is too small. Received {1}. Adjusting to {2}",
                        nameof(receiveHangDetectionTimeSeconds),
                        receiveHangDetectionTimeSeconds,
                        minReceiveHangDetectionTimeSeconds);
                    receiveHangDetectionTimeSeconds = minReceiveHangDetectionTimeSeconds;
                }
                if (receiveHangDetectionTimeSeconds > maxReceiveHangDetectionTimeSeconds)
                {
                    DefaultTrace.TraceWarning(
                        "The value of {0} is too large. Received {1}. Adjusting to {2}",
                        nameof(receiveHangDetectionTimeSeconds),
                        receiveHangDetectionTimeSeconds,
                        maxReceiveHangDetectionTimeSeconds);
                    receiveHangDetectionTimeSeconds = maxReceiveHangDetectionTimeSeconds;
                }
                const int minSendHangDetectionTimeSeconds = 2;
                const int maxSendHangDetectionTimeSeconds = 60;
                if (sendHangDetectionTimeSeconds < minSendHangDetectionTimeSeconds)
                {
                    DefaultTrace.TraceWarning(
                        "The value of {0} is too small. Received {1}. Adjusting to {2}",
                        nameof(sendHangDetectionTimeSeconds),
                        sendHangDetectionTimeSeconds,
                        minSendHangDetectionTimeSeconds);
                    sendHangDetectionTimeSeconds = minSendHangDetectionTimeSeconds;
                }
                if (sendHangDetectionTimeSeconds > maxSendHangDetectionTimeSeconds)
                {
                    DefaultTrace.TraceWarning(
                        "The value of {0} is too large. Received {1}. Adjusting to {2}",
                        nameof(sendHangDetectionTimeSeconds),
                        sendHangDetectionTimeSeconds,
                        maxSendHangDetectionTimeSeconds);
                    sendHangDetectionTimeSeconds = maxSendHangDetectionTimeSeconds;
                }
                this.fallbackClient = new RntbdTransportClient(
                    requestTimeoutInSeconds,
                    maxConcurrentConnectionOpenRequests,
                    userAgent,
                    overrideHostNameInCertificate,
                    openTimeoutInSeconds,
                    idleTimeoutInSeconds,
                    timerPoolGranularityInSeconds);
                this.transportClient = new Rntbd.TransportClient(
                    new Rntbd.TransportClient.Options(TimeSpan.FromSeconds(requestTimeoutInSeconds))
                {
                    MaxChannels              = maxRntbdChannels,
                    PartitionCount           = rntbdPartitionCount,
                    MaxRequestsPerChannel    = maxRequestsPerRntbdChannel,
                    ReceiveHangDetectionTime = TimeSpan.FromSeconds(receiveHangDetectionTimeSeconds),
                    SendHangDetectionTime    = TimeSpan.FromSeconds(sendHangDetectionTimeSeconds),
                    UserAgent = userAgent,
                    CertificateHostNameOverride = overrideHostNameInCertificate,
                    OpenTimeout         = TimeSpan.FromSeconds(openTimeoutInSeconds),
                    TimerPoolResolution = TimeSpan.FromSeconds(timerPoolGranularityInSeconds),
                    IdleTimeout         = TimeSpan.FromSeconds(idleTimeoutInSeconds),
                    EnableCpuMonitor    = enableCpuMonitor
                });
            }
            else
            {
                throw new ArgumentOutOfRangeException("protocol", protocol, "Invalid protocol value");
            }
            this.protocol = protocol;

            if (transportClientHandlerFactory != null)
            {
                this.fallbackClient  = transportClientHandlerFactory(this.fallbackClient);
                this.transportClient = transportClientHandlerFactory(this.transportClient);
            }
        }