/// <summary> /// Process actions in parallel. /// </summary> /// <param name="state"></param> protected override void Process(object state) { lock (m_actions) { // Init expected count. Lock is not needed since we don't expect app to add task while executing sequence but there is no harm. m_expectedCount = m_actions.Count; } bool done = false; while (!done) { AsyncTask task = null; lock (m_actions) { if (m_actions.Count > 0) { task = m_actions.Dequeue(); } } if (task == null) { done = true; // No more actions to execute. } else { Exception exception = null; task.TaskCompleted += delegate(object sender, AsyncTaskCompletedEventArgs e) { this.Logger.Log(Logger.LogLevel.Info, String.Format("**{0}({1})** <{2}> Started.", this.Name, this.Component.Name, task.Name)); this.AddCompletedAction(task); // Could have failed or succeeded. The method should take care of this. }; try { this.Logger.Log(Logger.LogLevel.Info, String.Format("**{0}({1})** <{2}> Starting.", this.Name, this.Component.Name, task.Name)); task.StartTask(); } catch (RealTimeException rte) { exception = rte; } catch (InvalidOperationException ivo) { exception = ivo; } finally { if (exception != null) { this.Logger.Log(Logger.LogLevel.Info, String.Format("**{0}({1})** Completed <{2}> with exception. {3}", this.Name, this.Component.Name, task.Name, exception.ToString())); this.AddCompletedAction(task); // This task resulted in exception. } } } } if (m_expectedCount == 0) { // It was empty list of actions to start with. this.CompleteSequence(null); } }
/// <summary> /// Process Sequence serially. /// </summary> protected virtual void Process(object state) { AsyncTaskResult previousActionResult = state as AsyncTaskResult; // Can be null. AsyncTask task = null; lock (m_actions) { m_pendingAction = null; if (m_actions.Count > 0) { task = m_actions.Dequeue(); m_pendingAction = task; } } if (task == null) { // No more items in queue. Complete the starup operaton if needed. this.CompleteSequence(null); } else { Exception exception = null; try { task.TaskCompleted += delegate(object sender, AsyncTaskCompletedEventArgs e) { AsyncTask reportingAction = sender as AsyncTask; if (!Object.ReferenceEquals(reportingAction, task)) { this.Logger.Log(Logger.LogLevel.Warning, String.Format("Reporting task does not match pending task. Task is probably completing twice. Task = {0}", reportingAction.Name)); return; // Ignore this reporting. } if (task.Exception != null && this.Component.Logger != null) { this.Component.Logger.Log(Logger.LogLevel.Verbose, String.Format("<{0}> completed with exception.", task.Name), task.Exception); } else { this.Component.Logger.Log(Logger.LogLevel.Verbose, String.Format("**{0}({1})** <{2}> Completed Task.", this.Name, this.Component.Name, task.Name)); } bool completionNeeded = false; Exception ex = task.Exception; if (task.Exception != null && !task.IsOptional) { completionNeeded = true; } if (completionNeeded) { this.CompleteSequence(ex); } else { // Make sure the task chained previous result, if any. if (previousActionResult != null) { AsyncTaskResult currActionResult = e.ActionResult; if (currActionResult == null) // This should not be null if Task always returned it. Play safe. { currActionResult = new AsyncTaskResult(task.Exception); } // If the task completing has task result, then we need to chain. If not create a new one. currActionResult.PreviousActionResult = previousActionResult; } // Continue processing. System.Threading.ThreadPool.QueueUserWorkItem(this.Process, e.ActionResult); } }; this.Component.Logger.Log(Logger.LogLevel.Verbose, String.Format("**{0}({1})** <{2}> Started Task.", this.Name, this.Component.Name, task.Name)); task.PreviousActionResult = previousActionResult; task.StartTask(); } catch (RealTimeException rte) { exception = rte; } catch (InvalidOperationException ivo) { exception = ivo; } finally { if (exception != null && !task.IsOptional) { this.Component.Logger.Log(Logger.LogLevel.Verbose, String.Format("**{0}({1})** Completing due to exception while starting <{2}>.", this.Name, this.Component.Name, task.Name), exception); this.CompleteSequence(exception); } else if (exception != null) { this.Component.Logger.Log(Logger.LogLevel.Verbose, String.Format("**{0}({1})** resuming after exception while starting <{2}>.", this.Name, this.Component.Name, task.Name), exception); // Continue processing. Ignore failuer in task. System.Threading.ThreadPool.QueueUserWorkItem(this.Process); } // else, wait for the task to complete. } } }
public void CreateOrGetUserEndpoint(AsyncTask task, object state) { string ownerUri = state as string; if (String.IsNullOrEmpty(ownerUri)) { task.Complete(new InvalidOperationException("OwnerUri is needed to request a user endpoint.")); return; } RealTimeAddress ownerAddress = null; try { ownerAddress = new RealTimeAddress(ownerUri); } catch (ArgumentException exception) { task.Complete(exception); return; } MyUserEndpoint myUserEndpoint = null; lock (this.SyncRoot) { if (m_userEndpoints.ContainsKey(ownerAddress)) { myUserEndpoint = m_userEndpoints[ownerAddress]; if (myUserEndpoint.UserEndpoint.State == LocalEndpointState.Terminating || myUserEndpoint.UserEndpoint.State == LocalEndpointState.Terminated) { myUserEndpoint = null; // Loose it since it is going away. m_userEndpoints.Remove(ownerAddress); m_userEndpointReferenceCounts.Remove(ownerAddress); } else { int count = m_userEndpointReferenceCounts[ownerAddress]; count++; m_userEndpointReferenceCounts[ownerAddress] = count; } } if (myUserEndpoint == null) { // Create and add user endpoint into dictionary. // One could use the platform discover server from uri if the topology has DNS srv records for server auto discovery. // Normally, this would point to a director. Here, we will use the proxy of the application endpoint. UserEndpointSettings userEndpointSettings = new UserEndpointSettings(ownerUri, m_settings.ProxyHost, m_settings.ProxyPort); UserEndpoint userEndpoint = new UserEndpoint(m_parent.Platform, userEndpointSettings); myUserEndpoint = new MyUserEndpoint(userEndpoint); m_userEndpoints.Add(ownerAddress, myUserEndpoint); m_userEndpointReferenceCounts.Add(ownerAddress, 1); myUserEndpoint.UserEndpoint.StateChanged += UserEndpointStateChanged; // Ensures that only one registration per endpoint. } UserEndpointCreationActionResult result = new UserEndpointCreationActionResult(myUserEndpoint, null); task.TaskResult = result; // Store it for now. if (myUserEndpoint.UserEndpoint.State == LocalEndpointState.Established) { task.Complete(null, result); } else if (myUserEndpoint.UserEndpoint.State == LocalEndpointState.Establishing) { // Wait till the endpoint establish completes. lock (this.SyncRoot) { m_pendingUserEndpointCreationTasks.Add(task); } } else if (myUserEndpoint.UserEndpoint.State == LocalEndpointState.Idle) { AsyncTask establishTask = new AsyncTask(this.StartupUserEndpoint, myUserEndpoint.UserEndpoint); establishTask.TaskCompleted += delegate(object sender, AsyncTaskCompletedEventArgs e) { task.TaskResult.Exception = e.ActionResult.Exception; // Transfer task.Complete(e.ActionResult.Exception, task.TaskResult); lock (this.SyncRoot) { // Complete pending tasks foreach (AsyncTask pendingTask in m_pendingUserEndpointCreationTasks) { pendingTask.TaskResult.Exception = e.ActionResult.Exception; pendingTask.Complete(e.ActionResult.Exception, pendingTask.TaskResult); } m_pendingUserEndpointCreationTasks.Clear(); } }; establishTask.StartTask(); } } }