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, this); } var invoker = invokable.GetInvoker(typeManager, request.InterfaceId, message.GenericGrainType); if (invoker is IGrainExtensionMethodInvoker && !(target is IGrainExtension)) { // We are trying the invoke a grain extension method on a grain // -- most likely reason is that the dynamic extension is not installed for this grain // So throw a specific exception here rather than a general InvalidCastException var error = String.Format( "Extension not installed on grain {0} attempting to invoke type {1} from invokable {2}", target.GetType().FullName, invoker.GetType().FullName, invokable.GetType().FullName); var exc = new GrainExtensionNotInstalledException(error); string extraDebugInfo = null; #if DEBUG extraDebugInfo = Utils.GetStackTrace(); #endif logger.Warn(ErrorCode.Stream_ExtensionNotInstalled, string.Format("{0} for message {1} {2}", error, message, extraDebugInfo), exc); throw exc; } resultObject = await InvokeWithInterceptors(target, request, invoker); } 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); } }
private void SendRequestMessage( GrainReference target, Message message, TaskCompletionSource<object> context, Action<Message, TaskCompletionSource<object>> callback, string debugContext, InvokeMethodOptions options, string genericArguments = null) { // fill in sender if (message.SendingSilo == null) message.SendingSilo = MySilo; if (!String.IsNullOrEmpty(genericArguments)) message.GenericGrainType = genericArguments; SchedulingContext schedulingContext = RuntimeContext.Current != null ? RuntimeContext.Current.ActivationContext as SchedulingContext : null; ActivationData sendingActivation = null; if (schedulingContext == null) { throw new InvalidOperationException( String.Format("Trying to send a message {0} on a silo not from within grain and not from within system target (RuntimeContext is not set to SchedulingContext) " + "RuntimeContext.Current={1} TaskScheduler.Current={2}", message, RuntimeContext.Current == null ? "null" : RuntimeContext.Current.ToString(), TaskScheduler.Current)); } switch (schedulingContext.ContextType) { case SchedulingContextType.SystemThread: throw new ArgumentException( String.Format("Trying to send a message {0} on a silo not from within grain and not from within system target (RuntimeContext is of SchedulingContextType.SystemThread type)", message), "context"); case SchedulingContextType.Activation: message.SendingActivation = schedulingContext.Activation.ActivationId; message.SendingGrain = schedulingContext.Activation.Grain; sendingActivation = schedulingContext.Activation; break; case SchedulingContextType.SystemTarget: message.SendingActivation = schedulingContext.SystemTarget.ActivationId; message.SendingGrain = ((ISystemTargetBase)schedulingContext.SystemTarget).GrainId; break; } // fill in destination var targetGrainId = target.GrainId; message.TargetGrain = targetGrainId; if (targetGrainId.IsSystemTarget) { SiloAddress targetSilo = (target.SystemTargetSilo ?? MySilo); message.TargetSilo = targetSilo; message.TargetActivation = ActivationId.GetSystemActivation(targetGrainId, targetSilo); message.Category = targetGrainId.Equals(Constants.MembershipOracleId) ? Message.Categories.Ping : Message.Categories.System; } if (target.IsObserverReference) { message.TargetObserverId = target.ObserverId; } if (debugContext != null) message.DebugContext = debugContext; var oneWay = (options & InvokeMethodOptions.OneWay) != 0; if (context == null && !oneWay) logger.Warn(ErrorCode.IGC_SendRequest_NullContext, "Null context {0}: {1}", message, Utils.GetStackTrace()); if (message.IsExpirableMessage(Config.Globals)) message.Expiration = DateTime.UtcNow + ResponseTimeout + Constants.MAXIMUM_CLOCK_SKEW; if (!oneWay) { var callbackData = new CallbackData( callback, tryResendMessage, context, message, unregisterCallback, Config.Globals); callbacks.TryAdd(message.Id, callbackData); callbackData.StartTimer(ResponseTimeout); } if (targetGrainId.IsSystemTarget) { // Messages to system targets bypass the task system and get sent "in-line" dispatcher.TransportMessage(message); } else { dispatcher.SendMessage(message, sendingActivation); } }