Example #1
0
        protected override HttpTransport DoAcquireTransport(EndpointAssignment assignment, bool reserve)
        {
            if (reserve)
            {
                return(new HttpTransport(assignment));
            }

            if (m_Transports.TryGetValue(assignment, out var transport))
            {
                return(transport);
            }
            lock (m_TransportLock)
            {
                if (m_Transports.TryGetValue(assignment, out transport))
                {
                    return(transport);
                }

                transport = new HttpTransport(assignment);
                var dict = new Dictionary <EndpointAssignment, HttpTransport>(m_Transports);
                dict[assignment] = transport;
                Thread.MemoryBarrier();
                m_Transports = dict;
            }

            return(transport);
        }
Example #2
0
 protected internal HttpTransport(EndpointAssignment assignment)
 {
     m_Assignment = assignment;
 }
Example #3
0
        /// <summary>
        /// Performs a Http/s call to a remote service pointed to by a EndpointAssigment object.
        /// An actual call is performed in a passed-in call body functor.
        /// </summary>
        /// <typeparam name="TResult">The resulting type of the call, as obtained from call body</typeparam>
        /// <param name="assignment">An endpoint assignment to call</param>
        /// <param name="body">Call body functor. May not be null</param>
        /// <param name="cancellation">Optional CancellationToken</param>
        /// <returns>TResult call result or throws `ClientException` if call failed </returns>
        public static async Task <TResult> CallOne <TResult>(this EndpointAssignment assignment,
                                                             Func <IHttpTransport, CancellationToken?, Task <TResult> > body,
                                                             CancellationToken?cancellation = null)
        {
            body.NonNull(nameof(body));
            if (!assignment.IsAssigned)
            {
                throw new ClientException(StringConsts.HTTP_CLIENT_CALL_ASSIGMENT_ERROR.Args("No assignments provided"));
            }

            var service = assignment.Endpoint.Service as IHttpService;

            if (service == null)
            {
                throw new ClientException(StringConsts.HTTP_CLIENT_CALL_ASSIGMENT_ERROR.Args("Wrong service type assignments"));
            }

            Exception cause = null;

            if (assignment.Endpoint.IsAvailable)
            {
                var ep        = assignment.Endpoint as IEndpointImplementation;
                var transport = service.AcquireTransport(assignment);
                try
                {
                    var http   = (transport as IHttpTransport).NonNull("Implementation error: cast to IHttpTransport");
                    var result = await body(http, cancellation).ConfigureAwait(false);

                    CallGuardException.Protect(ep, _ => _.NotifyCallSuccess(transport));
                    return(result);
                }
                catch (Exception error)
                {
                    //Implementation error
                    if (error is CallGuardException)
                    {
                        throw;
                    }

                    //TaskCanceledException gets thrown on simple timeout even when cancellation was NOT requested
                    if (error is TaskCanceledException && cancellation.HasValue && cancellation.Value.IsCancellationRequested)
                    {
                        throw;
                    }

                    var errorClass = ep.NotifyCallError(transport, error);
                    //todo instrument

                    if (errorClass == CallErrorClass.ServiceLogic)
                    {
                        throw;                                 //throw logical errors
                    }
                    cause = error;
                }
                finally
                {
                    service.ReleaseTransport(transport);
                }
            }
            else
            {
                cause = new ClientException("Endpoint !Available");
            }

            var toThrow = new ClientException(StringConsts.HTTP_CLIENT_CALL_FAILED
                                              .Args(service.GetType().Name,
                                                    assignment.MappedRemoteAddress.TakeLastChars(32, "..."),
                                                    1),
                                              cause);

            if (service.ComponentEffectiveLogLevel <= Log.MessageType.Error)
            {
                service.App.Log.Write(
                    new Log.Message
                {
                    Topic     = service.ComponentLogTopic,
                    Type      = Log.MessageType.Error,
                    From      = "{0}{1}.{2}".Args(service.ComponentLogFromPrefix, nameof(HttpCallExtensions), nameof(Call)),
                    Text      = "Service `{0}` call error: {1}".Args(service.Name, toThrow.ToMessageWithType()),
                    Exception = toThrow,
                    RelatedTo = (Ambient.CurrentCallFlow?.ID) ?? Guid.Empty
                });
            }

            throw toThrow;
        }//CallOne