/// <summary> /// Enqueue message for local handling after transaction completes /// </summary> /// <param name="message"></param> /// <param name="targetActivation"></param> private void EnqueueRequest(Message message, ActivationData targetActivation) { var overloadException = targetActivation.CheckOverloaded(logger); if (overloadException != null) { MessagingProcessingStatisticsGroup.OnDispatcherMessageProcessedError(message, "Overload2"); RejectMessage(message, Message.RejectionTypes.Overloaded, overloadException, "Target activation is overloaded " + targetActivation); return; } if (Message.WriteMessagingTraces) { message.AddTimestamp(Message.LifecycleTag.EnqueueWaiting); } bool enqueuedOk = targetActivation.EnqueueMessage(message); if (!enqueuedOk) { ProcessRequestToInvalidActivation(message, targetActivation.Address, targetActivation.ForwardingAddress, "EnqueueRequest"); } // Dont count this as end of processing. The message will come back after queueing via HandleIncomingRequest. #if DEBUG // This is a hot code path, so using #if to remove diags from Release version // Note: Caller already holds lock on activation if (logger.IsVerbose2) { logger.Verbose2(ErrorCode.Dispatcher_EnqueueMessage, "EnqueueMessage for {0}: targetActivation={1}", message.TargetActivation, targetActivation.DumpStatus()); } #endif }
public Message CreateResponseMessage() { var response = new Message(this.Category, Directions.Response) { Id = this.Id, IsReadOnly = this.IsReadOnly, IsAlwaysInterleave = this.IsAlwaysInterleave, TargetSilo = this.SendingSilo }; if (this.ContainsHeader(Header.SENDING_GRAIN)) { response.SetHeader(Header.TARGET_GRAIN, this.GetHeader(Header.SENDING_GRAIN)); if (this.ContainsHeader(Header.SENDING_ACTIVATION)) { response.SetHeader(Header.TARGET_ACTIVATION, this.GetHeader(Header.SENDING_ACTIVATION)); } } response.SendingSilo = this.TargetSilo; if (this.ContainsHeader(Header.TARGET_GRAIN)) { response.SetHeader(Header.SENDING_GRAIN, this.GetHeader(Header.TARGET_GRAIN)); if (this.ContainsHeader(Header.TARGET_ACTIVATION)) { response.SetHeader(Header.SENDING_ACTIVATION, this.GetHeader(Header.TARGET_ACTIVATION)); } else if (this.TargetGrain.IsSystemTarget) { response.SetHeader(Header.SENDING_ACTIVATION, ActivationId.GetSystemActivation(TargetGrain, TargetSilo)); } } if (this.ContainsHeader(Header.TIMESTAMPS)) { response.SetHeader(Header.TIMESTAMPS, this.GetHeader(Header.TIMESTAMPS)); } if (this.ContainsHeader(Header.DEBUG_CONTEXT)) { response.SetHeader(Header.DEBUG_CONTEXT, this.GetHeader(Header.DEBUG_CONTEXT)); } if (this.ContainsHeader(Header.CACHE_INVALIDATION_HEADER)) { response.SetHeader(Header.CACHE_INVALIDATION_HEADER, this.GetHeader(Header.CACHE_INVALIDATION_HEADER)); } if (this.ContainsHeader(Header.EXPIRATION)) { response.SetHeader(Header.EXPIRATION, this.GetHeader(Header.EXPIRATION)); } if (Message.WriteMessagingTraces) { response.AddTimestamp(LifecycleTag.CreateResponse); } RequestContext.ExportToMessage(response); return(response); }
// Check if it is OK to receive a message to its current target activation. private bool SiloCanAcceptRequest(Message message) { if (Message.WriteMessagingTraces) { message.AddTimestamp(Message.LifecycleTag.TaskIncoming); } return(!catalog.SiloStatusOracle.CurrentStatus.IsTerminating()); }
public void DoCallback(Message response) { if (alreadyFired) { return; } lock (this) { if (alreadyFired) { return; } if (response.Result == Message.ResponseTypes.Rejection && response.RejectionType == Message.RejectionTypes.Transient) { if (resendFunc(Message)) { return; } } alreadyFired = true; DisposeTimer(); if (StatisticsCollector.CollectApplicationRequestsStats) { timeSinceIssued.Stop(); } if (unregister != null) { unregister(); } } if (Message.WriteMessagingTraces) { response.AddTimestamp(Message.LifecycleTag.InvokeIncoming); } if (logger.IsVerbose2) { logger.Verbose2("Message {0} timestamps: {1}", response, response.GetTimestampString()); } if (StatisticsCollector.CollectApplicationRequestsStats) { ApplicationRequestsStatisticsGroup.OnAppRequestsEnd(timeSinceIssued.Elapsed); } // do callback outside the CallbackData lock. Just not a good practice to hold a lock for this unrelated operation. callback(response, context); }
/// <summary> /// Handle an incoming message and queue/invoke appropriate handler /// </summary> /// <param name="message"></param> /// <param name="targetActivation"></param> public void HandleIncomingRequest(Message message, ActivationData targetActivation) { lock (targetActivation) { if (targetActivation.State == ActivationState.Invalid) { ProcessRequestToInvalidActivation(message, targetActivation.Address, targetActivation.ForwardingAddress, "HandleIncomingRequest"); return; } // Now we can actually scheduler processing of this request targetActivation.RecordRunning(message); var context = new SchedulingContext(targetActivation); if (Message.WriteMessagingTraces) { message.AddTimestamp(Message.LifecycleTag.EnqueueWorkItem); } MessagingProcessingStatisticsGroup.OnDispatcherMessageProcessedOk(message); Scheduler.QueueWorkItem(new InvokeWorkItem(targetActivation, message, context), context); } }
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; } //MessagingProcessingStatisticsGroup.OnRequestProcessed(message, "Invoked"); if (Message.WriteMessagingTraces) { message.AddTimestamp(Message.LifecycleTag.InvokeIncoming); } 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); } var invoker = invokable.GetInvoker(message.InterfaceId, message.GenericGrainType); object resultObject; try { var request = (InvokeMethodRequest)message.BodyObject; 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 = new StackTrace().ToString(); #endif logger.Warn(ErrorCode.Stream_ExtensionNotInstalled, string.Format("{0} for message {1} {2}", error, message, extraDebugInfo), exc); throw exc; } resultObject = await invoker.Invoke(target, request.InterfaceId, request.MethodId, request.Arguments); } 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 InvalidExpressionException( 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 = 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, new StackTrace()); } if (Message.WriteMessagingTraces) { message.AddTimestamp(Message.LifecycleTag.Create); } 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(message.Id), 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); } }
/// <summary> /// Enqueue message for local handling after transaction completes /// </summary> /// <param name="message"></param> /// <param name="targetActivation"></param> private void EnqueueRequest(Message message, ActivationData targetActivation) { var overloadException = targetActivation.CheckOverloaded(logger); if (overloadException != null) { MessagingProcessingStatisticsGroup.OnDispatcherMessageProcessedError(message, "Overload2"); RejectMessage(message, Message.RejectionTypes.Overloaded, overloadException, "Target activation is overloaded " + targetActivation); return; } if (Message.WriteMessagingTraces) message.AddTimestamp(Message.LifecycleTag.EnqueueWaiting); bool enqueuedOk = targetActivation.EnqueueMessage(message); if (!enqueuedOk) { ProcessRequestToInvalidActivation(message, targetActivation.Address, targetActivation.ForwardingAddress, "EnqueueRequest"); } // Dont count this as end of processing. The message will come back after queueing via HandleIncomingRequest. #if DEBUG // This is a hot code path, so using #if to remove diags from Release version // Note: Caller already holds lock on activation if (logger.IsVerbose2) logger.Verbose2(ErrorCode.Dispatcher_EnqueueMessage, "EnqueueMessage for {0}: targetActivation={1}", message.TargetActivation, targetActivation.DumpStatus()); #endif }
/// <summary> /// Handle an incoming message and queue/invoke appropriate handler /// </summary> /// <param name="message"></param> /// <param name="targetActivation"></param> public void HandleIncomingRequest(Message message, ActivationData targetActivation) { lock (targetActivation) { if (targetActivation.State == ActivationState.Invalid) { ProcessRequestToInvalidActivation(message, targetActivation.Address, targetActivation.ForwardingAddress, "HandleIncomingRequest"); return; } // Now we can actually scheduler processing of this request targetActivation.RecordRunning(message); var context = new SchedulingContext(targetActivation); if (Message.WriteMessagingTraces) message.AddTimestamp(Message.LifecycleTag.EnqueueWorkItem); MessagingProcessingStatisticsGroup.OnDispatcherMessageProcessedOk(message); Scheduler.QueueWorkItem(new InvokeWorkItem(targetActivation, message, context), context); } }
public void DoCallback(Message response) { if (alreadyFired) return; lock (this) { if (alreadyFired) return; if (response.Result == Message.ResponseTypes.Rejection && response.RejectionType == Message.RejectionTypes.Transient) { if (resendFunc(Message)) { return; } } alreadyFired = true; DisposeTimer(); if (StatisticsCollector.CollectApplicationRequestsStats) { timeSinceIssued.Stop(); } if (unregister != null) { unregister(); } } if (Message.WriteMessagingTraces) response.AddTimestamp(Message.LifecycleTag.InvokeIncoming); if (logger.IsVerbose2) logger.Verbose2("Message {0} timestamps: {1}", response, response.GetTimestampString()); if (StatisticsCollector.CollectApplicationRequestsStats) { ApplicationRequestsStatisticsGroup.OnAppRequestsEnd(timeSinceIssued.Elapsed); } // do callback outside the CallbackData lock. Just not a good practice to hold a lock for this unrelated operation. callback(response, context); }