Exemple #1
0
        /// <summary>
        /// Handles the an InvokeMethodRequest message on given target.
        /// </summary>
        /// <remarks>
        /// Options when we receive a InvokeMethodRequest
        /// ----------------------------------------------
        /// 1) Intercepted RPC
        /// 2) Request to start a reactive computation for this method invocation
        /// 3) KeepAlive request of the reactive computation for this method invocation
        /// 4) Normal Application RPC
        /// 5) System RPC
        /// </remarks>
        /// <returns></returns>
        internal async Task Invoke(IAddressable target, IInvokable invokable, Message message)
        {
            try
            {
                // Don't process messages that have already timed out
                if (message.IsExpired)
                {
                    message.DropExpiredMessage(MessagingStatisticsGroup.Phase.Invoke);
                    return;
                }

                RequestContext.Import(message.RequestContextData);
                if (Config.Globals.PerformDeadlockDetection && !message.TargetGrain.IsSystemTarget)
                {
                    UpdateDeadlockInfoInRequestContext(new RequestInvocationHistory(message));
                    // RequestContext is automatically saved in the msg upon send and propagated to the next hop
                    // in RuntimeClient.CreateMessage -> RequestContext.ExportToMessage(message);
                }

                object resultObject;
                try
                {
                    var request = (InvokeMethodRequest)message.BodyObject;
                    if (request.Arguments != null)
                    {
                        CancellationSourcesExtension.RegisterCancellationTokens(target, request, logger);
                    }

                    // Get the invoker for this invocation
                    IGrainMethodInvoker invoker = GetGrainMethodInvoker(target, invokable, message, request);

                    // Check whether this call should be intercepted
                    var siloWideInterceptor  = SiloProviderRuntime.Instance.GetInvokeInterceptor();
                    var grainWithInterceptor = target as IGrainInvokeInterceptor;

                    // Silo-wide interceptors do not operate on system targets.
                    var hasSiloWideInterceptor   = siloWideInterceptor != null && target is IGrain;
                    var hasGrainLevelInterceptor = grainWithInterceptor != null;

                    // Normal Application Call = an application call made from grain to grain or from client to grain.
                    // Some system-related calls such as the IReminderTable are encoded as Application messages, therefore we needed this check.
                    var NormalApplicationCall = message.Category == Message.Categories.Application && message.TargetGrain.IsGrain && (message.SendingGrain.IsGrain || message.SendingGrain.IsClient);

                    // 1) If the target has a grain-level interceptor or there is a silo-level interceptor, intercept the
                    // call.
                    if (hasGrainLevelInterceptor || hasSiloWideInterceptor)
                    {
                        resultObject = await InvokeWithInterceptors(target, request, invoker, hasSiloWideInterceptor, siloWideInterceptor, hasGrainLevelInterceptor, grainWithInterceptor);
                    }

                    else if (NormalApplicationCall)
                    {
                        // 2) Request to start a reactive computation for this method invocation
                        if (message.IsRcExecute())
                        {
                            HandleReactiveComputationExecute(target, request, message, invoker);
                            return; // Does not expect a return (OneWay Message)
                        }

                        // 3) Refresh Reactive Computation Subscription
                        else if (message.IsRcKeepAlive())
                        {
                            HandleReactiveComputationExecute(target, request, message, invoker, true);
                            return; // Does not expect a return (OneWay Message)
                        }

                        // 4) Normal application RPC call
                        else
                        {
                            // Invoke the method
                            resultObject = await invoker.Invoke(target, request);

                            // Check if there are any active reactive computations in this grain that require recomputation after this call
                            InsideRcManager.RecomputeSummaries();
                        }
                    }

                    // 5) System RPC call
                    else
                    {
                        resultObject = await invoker.Invoke(target, request);
                    }
                }
                catch (Exception exc1)
                {
                    if (invokeExceptionLogger.IsVerbose || message.Direction == Message.Directions.OneWay)
                    {
                        invokeExceptionLogger.Warn(ErrorCode.GrainInvokeException,
                                                   "Exception during Grain method call of message: " + message, exc1);
                    }
                    if (message.Direction != Message.Directions.OneWay)
                    {
                        SafeSendExceptionResponse(message, exc1);
                    }
                    return;
                }

                if (message.Direction == Message.Directions.OneWay)
                {
                    return;
                }

                SafeSendResponse(message, resultObject);
            }
            catch (Exception exc2)
            {
                logger.Warn(ErrorCode.Runtime_Error_100329, "Exception during Invoke of message: " + message, exc2);
                if (message.Direction != Message.Directions.OneWay)
                {
                    SafeSendExceptionResponse(message, exc2);
                }
            }
        }