private async Task LocalObjectMessagePumpAsync(LocalObjectData objectData) { while (true) { try { Message message; lock (objectData.Messages) { if (objectData.Messages.Count == 0) { objectData.Running = false; break; } message = objectData.Messages.Dequeue(); } if (ExpireMessageIfExpired(message, MessagingStatisticsGroup.Phase.Invoke)) { continue; } RequestContext.Import(message.RequestContextData); var request = (InvokeMethodRequest)message.GetDeserializedBody(this.SerializationManager); var targetOb = (IAddressable)objectData.LocalObject.Target; object resultObject = null; Exception caught = null; try { // exceptions thrown within this scope are not considered to be thrown from user code // and not from runtime code. var resultPromise = objectData.Invoker.Invoke(targetOb, request); if (resultPromise != null) // it will be null for one way messages { resultObject = await resultPromise; } } catch (Exception exc) { // the exception needs to be reported in the log or propagated back to the caller. caught = exc; } if (caught != null) { this.ReportException(message, caught); } else if (message.Direction != Message.Directions.OneWay) { await this.SendResponseAsync(message, resultObject); } } catch (Exception) { // ignore, keep looping. } } }
private void InvokeLocalObjectAsync(LocalObjectData objectData, Message message) { var obj = (IAddressable)objectData.LocalObject.Target; if (obj == null) { //// Remove from the dictionary record for the garbage collected object? But now we won't be able to detect invalid dispatch IDs anymore. logger.Warn(ErrorCode.Runtime_Error_100162, String.Format("Object associated with Grain ID {0} has been garbage collected. Deleting object reference and unregistering it. Message = {1}", objectData.Grain, message)); lock (localObjects) { // Try to remove. If it's not there, we don't care. localObjects.Remove(objectData.Grain); } UnregisterObjectReference(objectData.Grain).Ignore(); return; } bool start; lock (objectData.Messages) { objectData.Messages.Enqueue(message); start = !objectData.Running; objectData.Running = true; } if (logger.IsVerbose) { logger.Verbose("InvokeLocalObjectAsync {0} start {1}", message, start); } if (start) { // we use Task.Run() to ensure that the message pump operates asynchronously // with respect to the current thread. see // http://channel9.msdn.com/Events/TechEd/Europe/2013/DEV-B317#fbid=aIWUq0ssW74 // at position 54:45. // // according to the information posted at: // http://stackoverflow.com/questions/12245935/is-task-factory-startnew-guaranteed-to-use-another-thread-than-the-calling-thr // this idiom is dependent upon the a TaskScheduler not implementing the // override QueueTask as task inlining (as opposed to queueing). this seems // implausible to the author, since none of the .NET schedulers do this and // it is considered bad form (the OrleansTaskScheduler does not do this). // // if, for some reason this doesn't hold true, we can guarantee what we // want by passing a placeholder continuation token into Task.StartNew() // instead. i.e.: // // return Task.StartNew(() => ..., new CancellationToken()); Func <Task> asyncFunc = async() => await this.LocalObjectMessagePumpAsync(objectData); Task.Run(asyncFunc).Ignore(); } }
private async Task LocalObjectMessagePumpAsync(LocalObjectData objectData) { while (true) { try { Message message; lock (objectData.Messages) { if (objectData.Messages.Count == 0) { objectData.Running = false; break; } message = objectData.Messages.Dequeue(); } if (ExpireMessageIfExpired(message, MessagingStatisticsGroup.Phase.Invoke)) continue; RequestContext.Import(message.RequestContextData); var request = (InvokeMethodRequest)message.BodyObject; var targetOb = (IAddressable)objectData.LocalObject.Target; object resultObject = null; Exception caught = null; try { // exceptions thrown within this scope are not considered to be thrown from user code // and not from runtime code. var resultPromise = objectData.Invoker.Invoke( targetOb, request.InterfaceId, request.MethodId, request.Arguments); if (resultPromise != null) // it will be null for one way messages { resultObject = await resultPromise; } } catch (Exception exc) { // the exception needs to be reported in the log or propagated back to the caller. caught = exc; } if (caught != null) this.ReportException(message, caught); else if (message.Direction != Message.Directions.OneWay) await this.SendResponseAsync(message, resultObject); }catch(Exception) { // ignore, keep looping. } } }
private void InvokeLocalObjectAsync(LocalObjectData objectData, Message message) { var obj = (IAddressable)objectData.LocalObject.Target; if (obj == null) { //// Remove from the dictionary record for the garbage collected object? But now we won't be able to detect invalid dispatch IDs anymore. logger.Warn(ErrorCode.Runtime_Error_100162, String.Format("Object associated with Observer ID {0} has been garbage collected. Deleting object reference and unregistering it. Message = {1}", objectData.ObserverId, message)); LocalObjectData ignore; // Try to remove. If it's not there, we don't care. localObjects.TryRemove(objectData.ObserverId, out ignore); return; } bool start; lock (objectData.Messages) { objectData.Messages.Enqueue(message); start = !objectData.Running; objectData.Running = true; } if (logger.IsVerbose) logger.Verbose("InvokeLocalObjectAsync {0} start {1}", message, start); if (start) { // we use Task.Run() to ensure that the message pump operates asynchronously // with respect to the current thread. see // http://channel9.msdn.com/Events/TechEd/Europe/2013/DEV-B317#fbid=aIWUq0ssW74 // at position 54:45. // // according to the information posted at: // http://stackoverflow.com/questions/12245935/is-task-factory-startnew-guaranteed-to-use-another-thread-than-the-calling-thr // this idiom is dependent upon the a TaskScheduler not implementing the // override QueueTask as task inlining (as opposed to queueing). this seems // implausible to the author, since none of the .NET schedulers do this and // it is considered bad form (the OrleansTaskScheduler does not do this). // // if, for some reason this doesn't hold true, we can guarantee what we // want by passing a placeholder continuation token into Task.StartNew() // instead. i.e.: // // return Task.StartNew(() => ..., new CancellationToken()); Func<Task> asyncFunc = async () => await this.LocalObjectMessagePumpAsync(objectData); Task.Run(asyncFunc).Ignore(); } }
private void Invoke(LocalObjectData objectData, Message message) { var obj = (IAddressable)objectData.LocalObject.Target; if (obj == null) { //// Remove from the dictionary record for the garbage collected object? But now we won't be able to detect invalid dispatch IDs anymore. this.logger.Warn( ErrorCode.Runtime_Error_100162, string.Format( "Object associated with Observer ID {0} has been garbage collected. Deleting object reference and unregistering it. Message = {1}", objectData.ObserverId, message)); // Try to remove. If it's not there, we don't care. this.TryDeregister(objectData.ObserverId); return; } bool start; lock (objectData.Messages) { objectData.Messages.Enqueue(message); start = !objectData.Running; objectData.Running = true; } if (this.logger.IsEnabled(LogLevel.Trace)) { this.logger.Trace($"InvokeLocalObjectAsync {message} start {start}"); } if (start) { // we want to ensure that the message pump operates asynchronously // with respect to the current thread. see // http://channel9.msdn.com/Events/TechEd/Europe/2013/DEV-B317#fbid=aIWUq0ssW74 // at position 54:45. // // according to the information posted at: // http://stackoverflow.com/questions/12245935/is-task-factory-startnew-guaranteed-to-use-another-thread-than-the-calling-thr // this idiom is dependent upon the a TaskScheduler not implementing the // override QueueTask as task inlining (as opposed to queueing). this seems // implausible to the author, since none of the .NET schedulers do this and // it is considered bad form (the OrleansTaskScheduler does not do this). // // if, for some reason this doesn't hold true, we can guarantee what we // want by passing a placeholder continuation token into Task.StartNew() // instead. i.e.: // // return Task.StartNew(() => ..., new CancellationToken()); // We pass these options to Task.Factory.StartNew as they make the call identical // to Task.Run. See: https://blogs.msdn.microsoft.com/pfxteam/2011/10/24/task-run-vs-task-factory-startnew/ Task.Factory.StartNew( this.dispatchFunc, objectData, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Ignore(); } }
private async Task LocalObjectMessagePumpAsync(LocalObjectData objectData) { while (true) { try { Message message; lock (objectData.Messages) { if (objectData.Messages.Count == 0) { objectData.Running = false; break; } message = objectData.Messages.Dequeue(); } if (message.IsExpired) { this.messagingTrace.OnDropExpiredMessage(message, MessagingStatisticsGroup.Phase.Invoke); continue; } RequestContextExtensions.Import(message.RequestContextData); InvokeMethodRequest request = null; try { request = (InvokeMethodRequest)message.BodyObject; } catch (Exception deserializationException) { if (this.logger.IsEnabled(LogLevel.Warning)) { this.logger.LogWarning( "Exception during message body deserialization in " + nameof(LocalObjectMessagePumpAsync) + " for message: {Message}, Exception: {Exception}", message, deserializationException); } this.runtimeClient.SendResponse(message, Response.ExceptionResponse(deserializationException)); continue; } var targetOb = (IAddressable)objectData.LocalObject.Target; object resultObject = null; Exception caught = null; try { // exceptions thrown within this scope are not considered to be thrown from user code // and not from runtime code. var resultPromise = objectData.Invoker.Invoke(objectData, request); if (resultPromise != null) // it will be null for one way messages { resultObject = await resultPromise; } } catch (Exception exc) { // the exception needs to be reported in the log or propagated back to the caller. caught = exc; } if (caught != null) { this.ReportException(message, caught); } else if (message.Direction != Message.Directions.OneWay) { this.SendResponseAsync(message, resultObject); } } catch (Exception outerException) { // ignore, keep looping. this.logger.LogWarning("Exception in " + nameof(LocalObjectMessagePumpAsync) + ": {Exception}", outerException); } finally { RequestContext.Clear(); } } }