private async Task <bool> TryHandleSpecialEndpoints(HttpListenerContext context)
        {
            try
            {
                foreach (var customEndpoint in CustomEndpoints)
                {
                    if (await customEndpoint.TryHandle(context,
                                                       (data, status, type) => TryWriteResponse(context, data, status, type)))
                    {
                        if (RequestTimings.Current.Request.ElapsedMS != null)
                        {
                            _metaEndpointsRoundtripTime.Record((long)RequestTimings.Current.Request.ElapsedMS,
                                                               TimeUnit.Milliseconds);
                        }
                        return(true);
                    }
                }
            }
            catch (Exception e)
            {
                var ex = GetRelevantException(e);
                await TryWriteResponse(context, ExceptionSerializer.Serialize(ex), GetExceptionStatusCode(ex));

                return(true);
            }

            return(false);
        }
        void ProcessIncomingRequest(ArraySegment <byte> data)
        {
            _receivedMessagesMeter.Mark();

            Message msg;

            if (MessageSerializer.TryDeserialize(data, out msg))
            {
                Logger.NetChannelHasReceivedMessage(Node, this, msg);
                var operationHeader = msg.GetHeader <OperationHeader>();
                if (operationHeader != null && operationHeader.Type == OperationType.Reply)
                {
                    PendingOperation continuation;
                    if (PendingOperationsByRequestId.TryRemove(operationHeader.RequestId, out continuation))
                    {
                        continuation.Expiration.Cancel();
                        if (!continuation.TCS.Task.IsCompleted)
                        {
                            var durationMs = (DateTime.Now - continuation.StartTime).TotalMilliseconds;
                            _requestDurationTimer.Record(durationMs, TimeUnit.Milliseconds);
                            Logger.NetChannelRequestCompleted(Node, this, msg, operationHeader.RequestId, durationMs);

                            var invMsg = msg as ErrorMessage;
                            if (invMsg != null)
                            {
                                _requestsFailedMeter.Mark();
                                Logger.NetChannelRequestFailed(Node, this, invMsg, operationHeader.RequestId, durationMs);
                                continuation.TCS.SetException(new ProcessingException(invMsg.ErrorCode, invMsg.ErrorString));
                            }
                            else
                            {
                                continuation.TCS.SetResult(msg);
                            }
                        }
                    }
                    else
                    {
                        OnIncomingMessage(msg);
                    }
                }
                else
                {
                    OnIncomingMessage(msg);
                }
            }
        }
示例#3
0
 public void Record(long time, string userValue = null)
 {
     timer.Record(time, Metrics_Net.TimeUnit.Milliseconds, userValue);
 }
        private async Task HandleRequest(HttpListenerContext context, long ticks, long timeFromLastReq)
        {
            try
            {
                var deltaDelayTicks = DateTime.UtcNow.Ticks - ticks;
                var sw = Stopwatch.StartNew();
                RequestTimings.ClearCurrentTimings();
                using (context.Response)
                {
                    // Special endpoints should not be logged/measured/traced like regular endpoints
                    // Access is allowed without HTTPS verifications since they don't expose anything sensitive (e.g. config values are encrypted)
                    if (await TryHandleSpecialEndpoints(context))
                    {
                        return;
                    }

                    // Regular endpoint handling
                    using (_activeRequestsCounter.NewContext("Request"))
                    {
                        RequestTimings.GetOrCreate(); // initialize request timing context

                        string methodName = null;
                        // Initialize with empty object for protocol backwards-compatibility.

                        var requestData = new HttpServiceRequest {
                            TracingData = new TracingData()
                        };
                        object[]         argumentsWithDefaults = null;
                        ServiceMethod    serviceMethod         = null;
                        ServiceCallEvent callEvent             = _serverRequestPublisher.GetNewCallEvent();
                        try
                        {
                            try
                            {
                                await CheckSecureConnection(context);

                                ValidateRequest(context);

                                requestData = await ParseRequest(context);


                                //-----------------------------------------------------------------------------------------
                                // Don't move TracingContext writes main flow, IT have to be here, to avoid side changes
                                //-----------------------------------------------------------------------------------------
                                TracingContext.SetRequestID(requestData.TracingData.RequestID);
                                TracingContext.SpanStartTime    = requestData.TracingData.SpanStartTime;
                                TracingContext.AbandonRequestBy = requestData.TracingData.AbandonRequestBy;
                                TracingContext.SetParentSpan(
                                    requestData.TracingData.SpanID ?? Guid.NewGuid().ToString("N"));
                                TracingContext.SetOverrides(requestData.Overrides);
                                if (requestData.TracingData.Tags != null)
                                {
                                    TracingContext.Tags = new ContextTags(requestData.TracingData.Tags);
                                }
                                TracingContext.AdditionalProperties = requestData.TracingData.AdditionalProperties;

                                callEvent.ServiceMethodSchema = context.Request.IsSecureConnection ? "HTTPS" : "HTTP";
                                SetCallEventRequestData(callEvent, requestData);

                                serviceMethod = ServiceEndPointDefinition.Resolve(requestData.Target);
                                callEvent.CalledServiceName = serviceMethod.GrainInterfaceType.Name;
                                methodName = serviceMethod.ServiceInterfaceMethod.Name;
                                var arguments = requestData.Target.IsWeaklyTyped
                                    ? GetParametersByName(serviceMethod, requestData.Arguments)
                                    : requestData.Arguments.Values.Cast <object>().ToArray();
                                argumentsWithDefaults =
                                    GetConvertedAndDefaultArguments(serviceMethod.ServiceInterfaceMethod, arguments);

                                if (_extendedDelayTimeLogging)
                                {
                                    callEvent.RecvDateTicks        = ticks;
                                    callEvent.ReqStartupDeltaTicks = deltaDelayTicks;
                                    callEvent.TimeFromLastReq      = timeFromLastReq;
                                    var outstandingReqs = Interlocked.Read(ref OutstandingRequests);
                                    callEvent.OutstandingRequests = outstandingReqs;
                                    if (deltaDelayTicks > 10_000_000)
                                    {
                                        callEvent.CollectionCountGen0 = GC.CollectionCount(0);
                                        callEvent.CollectionCountGen1 = GC.CollectionCount(1);
                                        callEvent.CollectionCountGen2 = GC.CollectionCount(2);
                                    }
                                }
                            }
                            catch (Exception e)
                            {
                                callEvent.Exception = e;
                                if (e is RequestException)
                                {
                                    throw;
                                }

                                throw new RequestException("Invalid request", e);
                            }

                            RejectRequestIfLateOrOverloaded();

                            var responseJson = await GetResponse(context, serviceMethod, requestData,
                                                                 argumentsWithDefaults);

                            if (await TryWriteResponse(context, responseJson, serviceCallEvent: callEvent))
                            {
                                callEvent.ErrCode = 0;
                                _successCounter.Increment();
                            }
                            else
                            {
                                _failureCounter.Increment();
                            }
                        }
                        catch (Exception e)
                        {
                            callEvent.Exception = callEvent.Exception ?? e;
                            _failureCounter.Increment();
                            Exception ex   = GetRelevantException(e);
                            string    json = _serializationTime.Time(() => ExceptionSerializer.Serialize(ex));
                            await TryWriteResponse(context, json, GetExceptionStatusCode(ex),
                                                   serviceCallEvent : callEvent);
                        }
                        finally
                        {
                            sw.Stop();
                            callEvent.ActualTotalTime = sw.Elapsed.TotalMilliseconds;

                            _roundtripTime.Record((long)(sw.Elapsed.TotalMilliseconds * 1000000),
                                                  TimeUnit.Nanoseconds);
                            if (methodName != null)
                            {
                                _endpointContext.Timer(methodName, Unit.Requests)
                                .Record((long)(sw.Elapsed.TotalMilliseconds * 1000000), TimeUnit.Nanoseconds);
                            }

                            _serverRequestPublisher.TryPublish(callEvent, argumentsWithDefaults, serviceMethod);
                        }
                    }
                }
            }
            finally
            {
                Interlocked.Decrement(ref OutstandingRequests);
            }
        }