/// <summary> /// Updates the progress rate and handles abnormal termination of the process. /// </summary> /// <param name="taskID">Task ID</param> /// <param name="userReturnValue">user parameter value</param> private void Update(int taskID, AsyncProcessingServiceReturnValue userReturnValue) { // Place the following statements in the loop, till the completion of task. // AsyncProcess: Loop-Start // Get command information from database to check for retry. this.GetCommandValue(taskID, userReturnValue); switch (userReturnValue.CommandId) { case (int)AsyncProcessingServiceParameterValue.AsyncCommand.Stop: // If you want to retry, then throw the following exception. throw new BusinessApplicationException("APSStopCommand", GetMessage.GetMessageDescription("CTE0003"), ""); case (int)AsyncProcessingServiceParameterValue.AsyncCommand.Abort: // Implement code to forcefully Abort the task. //... // If the task is abnormal terminated, then throw the exception . throw new BusinessSystemException("APSAbortCommand", GetMessage.GetMessageDescription("CTE0004")); default: // Update the progress rate in database. this.UpdateProgressRate(taskID, userReturnValue, 50); // Sleeps the thread, to minimize the CPU utilization. System.Threading.Thread.Sleep(this.NumberOfSeconds * 1000); break; } //AsyncProcess: Loop-End // If loop ends with no error, that indicates the task is completed sucessfully. return; }
/// <summary> /// Stop the asynchronous service and Waits to complete all worker thread to complete. /// </summary> public void StopAsyncProcess() { // Breaks the infinite loop of Main thread. this._infiniteLoop = false; // Wait the end of the main thread. this._mainThread.Join(); // Update stop command to all the running asynchronous task AsyncProcessingServiceParameterValue asyncParameterValue = new AsyncProcessingServiceParameterValue("AsyncProcessingService", "StopAllTask", "StopAllTask", "SQL", new MyUserInfo("AsyncProcessingService", "AsyncProcessingService")); asyncParameterValue.StatusId = (int)AsyncProcessingServiceParameterValue.AsyncStatus.Processing; asyncParameterValue.CommandId = (int)AsyncProcessingServiceParameterValue.AsyncCommand.Stop; LayerB layerB = new LayerB(); AsyncProcessingServiceReturnValue asyncReturnValue = (AsyncProcessingServiceReturnValue)layerB.DoBusinessLogic( (BaseParameterValue)asyncParameterValue, DbEnum.IsolationLevelEnum.ReadCommitted); if (asyncReturnValue.ErrorFlag) { LogIF.ErrorLog("ASYNC-SERVICE", "ErrorMessageID: " + asyncReturnValue.ErrorMessageID + "ErrorMessage: " + asyncReturnValue.ErrorMessage); } // Wait for all worker thread to be complete LogIF.InfoLog("ASYNC-SERVICE", GetMessage.GetMessageDescription("I0004")); while (this._workerThreadCount != 0) { // Wait for the completion of the worker thread. Thread.Sleep(this._numberOfSeconds * 1000); } // Log after completing all worker threads LogIF.InfoLog("ASYNC-SERVICE", GetMessage.GetMessageDescription("I0008")); }
/// <summary> /// Initiate the processing of asynchronous task. /// </summary> /// <param name="userParameterValue">asynchronous parameter values</param> public void UOC_Start(AsyncProcessingServiceParameterValue userParameterValue) { // Generates a return value class. AsyncProcessingServiceReturnValue userReturnValue = new AsyncProcessingServiceReturnValue(); this.ReturnValue = userReturnValue; // Get array data from serialized base64 string. byte[] arrayData = this.DeserializeFromBase64String(userParameterValue.Data); // Get command information from database to check for retry. this.GetCommandValue(userParameterValue.TaskId, userReturnValue); if (userReturnValue.CommandId == (int)AsyncProcessingServiceParameterValue.AsyncCommand.Stop) { // Retry task: to resume asynchronous process in the middle of the processing. this.ResumeProcessing(userParameterValue.TaskId, userReturnValue); // Updated progress rate will be taken as random number. ProgressRate = this.GenerateProgressRate(ProgressRate); } else { // Otherwise, implement code to initiating a new task. //... // Hence, initializing progress rate to zero. ProgressRate = 0; } // Updates the progress rate and handles abnormal termination of the process. this.Update(userParameterValue.TaskId, userReturnValue); }
/// <summary> /// Inserts async parameter values to database /// </summary> /// <param name="asyncParameterValue"></param> /// <param name="asyncReturnValue"></param> public void Insert(AsyncProcessingServiceParameterValue asyncParameterValue, AsyncProcessingServiceReturnValue asyncReturnValue) { string filename = string.Empty; // 静的SQL filename = "AsyncProcessingServiceInsert.sql"; // -- ファイルから読み込む場合。 this.SetSqlByFile2(filename); // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 this.SetParameter("P2", asyncParameterValue.UserId); this.SetParameter("P3", asyncParameterValue.ProcessName); this.SetParameter("P4", asyncParameterValue.Data); this.SetParameter("P5", asyncParameterValue.RegistrationDateTime); this.SetParameter("P6", asyncParameterValue.ExecutionStartDateTime); this.SetParameter("P7", asyncParameterValue.NumberOfRetries); this.SetParameter("P8", asyncParameterValue.CompletionDateTime); this.SetParameter("P9", asyncParameterValue.StatusId); this.SetParameter("P10", asyncParameterValue.ProgressRate); this.SetParameter("P11", asyncParameterValue.CommandId); this.SetParameter("P12", asyncParameterValue.ReservedArea); object obj; // -- 追加(件数を確認できる) obj = this.ExecInsUpDel_NonQuery(); // ↑DBアクセス----------------------------------------------------- // 戻り値を設定 asyncReturnValue.Obj = obj; }
/// <summary> /// Updates Async Parameter values to Database through LayerD /// </summary> /// <param name="asyncParameterValue"></param> private void UOC_Update(AsyncProcessingServiceParameterValue asyncParameterValue) { AsyncProcessingServiceReturnValue asyncReturnValue = new AsyncProcessingServiceReturnValue(); this.ReturnValue = asyncReturnValue; LayerD myDao = new LayerD(this.GetDam()); myDao.Update(asyncParameterValue, asyncReturnValue); }
/// <summary> /// Inserts Async Parameter values to Database through LayerD /// </summary> /// <param name="asyncParameterValue"></param> public void UOC_Start(AsyncProcessingServiceParameterValue asyncParameterValue) { // 戻り値クラスを生成して、事前に戻り地に設定しておく。 AsyncProcessingServiceReturnValue asyncReturnValue = new AsyncProcessingServiceReturnValue(); this.ReturnValue = asyncReturnValue; LayerD myDao = new LayerD(this.GetDam()); myDao.Insert(asyncParameterValue, asyncReturnValue); }
/// <summary> /// Updates the command of selected task /// </summary> /// <param name="taskID">Task ID</param> /// <param name="commandId">Command ID</param> /// <param name="userReturnValue">user parameter value</param> private void UpdateTaskCommand(int taskID, int commandId, AsyncProcessingServiceReturnValue userReturnValue) { // Sets parameters of AsyncProcessingServiceParameterValue to update the command of selected task. AsyncProcessingServiceParameterValue asyncParameterValue = new AsyncProcessingServiceParameterValue("AsyncProcessingService", "UpdateTaskCommand", "UpdateTaskCommand", "SQL", new MyUserInfo("AsyncProcessingService", "AsyncProcessingService")); asyncParameterValue.TaskId = taskID; asyncParameterValue.CommandId = commandId; // Calls data access part of asynchronous processing service. LayerD myDao = new LayerD(this.GetDam(this.DamKeyforAMT)); myDao.UpdateTaskCommand(asyncParameterValue, userReturnValue); }
/// <summary> /// Updates the progress rate and handles abnormal termination of the process. /// </summary> /// <param name="taskID">Task ID</param> /// <param name="userReturnValue">user parameter value</param> private void Update(int taskID, AsyncProcessingServiceReturnValue userReturnValue) { // Place the following statements in the loop, till the completion of task. while (true) { // Get command information from database to check for retry. this.GetCommandValue(taskID, userReturnValue); switch (userReturnValue.CommandId) { case (int)AsyncProcessingServiceParameterValue.AsyncCommand.Stop: // If you want to retry, then throw the following exception. throw new BusinessApplicationException("APSStopCommand", GetMessage.GetMessageDescription("CTE0003"), ""); case (int)AsyncProcessingServiceParameterValue.AsyncCommand.Abort: // Implement code to forcefully Abort the task. //... // If the task is abnormal terminated, then throw the exception . throw new BusinessSystemException("APSAbortCommand", GetMessage.GetMessageDescription("CTE0004")); default: // Generates new progress rate of the task. ProgressRate = this.GenerateProgressRate(ProgressRate); // Update the progress rate in database. this.UpdateProgressRate(taskID, userReturnValue, ProgressRate); if (ProgressRate < this.AbortPercentage) { // Update ABORT command to database this.UpdateTaskCommand(taskID, (int)AsyncProcessingServiceParameterValue.AsyncCommand.Abort, userReturnValue); } else if (ProgressRate < this.StopPercentage) { // Update STOP command to database this.UpdateTaskCommand(taskID, (int)AsyncProcessingServiceParameterValue.AsyncCommand.Stop, userReturnValue); } else if (ProgressRate == SUCCESS_STATE) { // Task is completed sucessfully. return; } // Sleeps the thread, to minimize the CPU utilization. System.Threading.Thread.Sleep(this.NumberOfSeconds * 1000); break; } } }
/// <summary> /// Updates the progress rate in the database. /// </summary> /// <param name="taskID">asynchronous task id</param> /// <param name="progressRate">progress rate</param> private void UpdateProgressRate(int taskID, AsyncProcessingServiceReturnValue userReturnValue, decimal progressRate) { // Sets parameters of AsyncProcessingServiceParameterValue to Update progress rate AsyncProcessingServiceParameterValue asyncParameterValue = new AsyncProcessingServiceParameterValue("AsyncProcessingService", "UpdateTaskProgress", "UpdateTaskProgress", "SQL", new MyUserInfo("AsyncProcessingService", "AsyncProcessingService")); asyncParameterValue.TaskId = taskID; asyncParameterValue.ProgressRate = progressRate; // Calls data access part of asynchronous processing service. LayerD myDao = new LayerD(this.GetDam(this.DamKeyforAMT)); myDao.UpdateTaskProgress(asyncParameterValue, userReturnValue); }
/// <summary> /// Get command information from database. /// </summary> /// <param name="taskID">asynchronous task id</param> /// <param name="userReturnValue">asynchronous return value</param> private void GetCommandValue(int taskID, AsyncProcessingServiceReturnValue userReturnValue) { // Sets parameters of AsyncProcessingServiceParameterValue to get command value. AsyncProcessingServiceParameterValue asyncParameterValue = new AsyncProcessingServiceParameterValue("AsyncProcessingService", "SelectCommand", "SelectCommand", "SQL", new MyUserInfo("AsyncProcessingService", "AsyncProcessingService")); asyncParameterValue.TaskId = taskID; // Calls data access part of asynchronous processing service. LayerD myDao = new LayerD(this.GetDam(this.DamKeyforAMT)); myDao.SelectCommand(asyncParameterValue, userReturnValue); userReturnValue.CommandId = (int)userReturnValue.Obj; }
/// <summary> /// Resumes asynchronous process in the middle of the processing. /// </summary> /// <param name="taskID">Task ID</param> /// <param name="userReturnValue">asynchronous return value</param> private void ResumeProcessing(int taskID, AsyncProcessingServiceReturnValue userReturnValue) { // Sets parameters of AsyncProcessingServiceParameterValue to resume asynchronous process in the middle of the processing. AsyncProcessingServiceParameterValue asyncParameterValue = new AsyncProcessingServiceParameterValue("AsyncProcessingService", "UpdateTaskCommand", "UpdateTaskCommand", "SQL", new MyUserInfo("AsyncProcessingService", "AsyncProcessingService")); asyncParameterValue.TaskId = taskID; asyncParameterValue.CommandId = 0; // Calls data access part of asynchronous processing service. LayerD myDao = new LayerD(this.GetDam(this.DamKeyforAMT)); myDao.UpdateTaskCommand(asyncParameterValue, userReturnValue); }
/// <summary> /// Updates the selected asynchronous task based type of SQL_Update_Method_name /// </summary> /// <param name="selectedAsyncTask">Selected Asynchronous Task</param> /// <param name="updateTask">SQL_Update_Method_name</param> /// <returns></returns> public AsyncProcessingServiceReturnValue UpdateAsyncTask(AsyncProcessingServiceReturnValue selectedAsyncTask, string updateTask, string exceptionInfo = null) { AsyncProcessingServiceParameterValue asyncParameterValue = new AsyncProcessingServiceParameterValue("AsyncProcessingService", updateTask, updateTask, "SQL", new MyUserInfo("AsyncProcessingService", "AsyncProcessingService")); asyncParameterValue.TaskId = selectedAsyncTask.TaskId; // Update databse based on task switch (updateTask) { case AsyncTaskUpdate.START: asyncParameterValue.ExecutionStartDateTime = DateTime.Now; asyncParameterValue.StatusId = (int)AsyncProcessingServiceParameterValue.AsyncStatus.Processing; break; case AsyncTaskUpdate.RETRY: if (exceptionInfo.Length > 512) { exceptionInfo = exceptionInfo.Substring(0, 512); } asyncParameterValue.NumberOfRetries = selectedAsyncTask.NumberOfRetries; asyncParameterValue.CompletionDateTime = DateTime.Now; asyncParameterValue.StatusId = (int)AsyncProcessingServiceParameterValue.AsyncStatus.AbnormalEnd; asyncParameterValue.ExceptionInfo = exceptionInfo; break; case AsyncTaskUpdate.FAIL: if (exceptionInfo.Length > 512) { exceptionInfo = exceptionInfo.Substring(0, 512); } asyncParameterValue.CompletionDateTime = DateTime.Now; asyncParameterValue.StatusId = (int)AsyncProcessingServiceParameterValue.AsyncStatus.Abort; asyncParameterValue.ExceptionInfo = exceptionInfo; break; case AsyncTaskUpdate.SUCCESS: asyncParameterValue.CompletionDateTime = DateTime.Now; asyncParameterValue.ProgressRate = 100; asyncParameterValue.StatusId = (int)AsyncProcessingServiceParameterValue.AsyncStatus.End; break; } LayerB layerB = new LayerB(); AsyncProcessingServiceReturnValue asyncReturnValue = (AsyncProcessingServiceReturnValue)layerB.DoBusinessLogic( (BaseParameterValue)asyncParameterValue, DbEnum.IsolationLevelEnum.ReadCommitted); return(asyncReturnValue); }
/// <summary> /// Maintains the single worker thread functionalities. /// </summary> /// <param name="asyncTask">Selected Asynchronous Task</param> private void WorkerThreadCallBack(object asyncTask) { AsyncProcessingServiceReturnValue selectedAsyncTask = (AsyncProcessingServiceReturnValue)asyncTask; // A new worker thread started an Async task this._workerThreadCount++; try { // To handle unstable "Register" state, when you invoke [Abort] at this state if (selectedAsyncTask.CommandId == (int)AsyncProcessingServiceParameterValue.AsyncCommand.Abort) { throw new BusinessSystemException("APSAbortCommand", GetMessage.GetMessageDescription("CTE0004")); } // Call User Program to execute by using communication control function AsyncProcessingServiceParameterValue asyncParameterValue = new AsyncProcessingServiceParameterValue("AsyncProcessingService", "Start", "Start", "SQL", new MyUserInfo(selectedAsyncTask.UserId, selectedAsyncTask.TaskId.ToString())); asyncParameterValue.TaskId = selectedAsyncTask.TaskId; asyncParameterValue.Data = selectedAsyncTask.Data; CallController callController = new CallController(asyncParameterValue.User); AsyncProcessingServiceReturnValue asyncReturnValue = (AsyncProcessingServiceReturnValue)callController.Invoke(selectedAsyncTask.ProcessName, asyncParameterValue); if (asyncReturnValue.ErrorFlag == true) { if (asyncReturnValue.ErrorMessageID == "APSStopCommand") { string exceptionInfo = "ErrorMessageID: " + asyncReturnValue.ErrorMessageID + Environment.NewLine + "ErrorMessage: " + asyncReturnValue.ErrorMessage; // Asynchronous task is stopped due to user 'stop' command. this.UpdateAsyncTask(selectedAsyncTask, AsyncTaskUpdate.RETRY, exceptionInfo); LogIF.ErrorLog("ASYNC-SERVICE", string.Format(GetMessage.GetMessageDescription("E0001") + asyncReturnValue.ErrorMessage, selectedAsyncTask.TaskId)); } else { // Exception occurred by other than BusinessApplicationException if (selectedAsyncTask.NumberOfRetries < this._maxNumberOfRetries) { // Asynchronous task does not exceeds the maximum number of retries // Updated as retry later string exceptionInfo = "ErrorMessageID: " + asyncReturnValue.ErrorMessageID + Environment.NewLine + "ErrorMessage: " + asyncReturnValue.ErrorMessage; selectedAsyncTask.NumberOfRetries += 1; this.UpdateAsyncTask(selectedAsyncTask, AsyncTaskUpdate.RETRY, exceptionInfo); LogIF.ErrorLog("ASYNC-SERVICE", string.Format(GetMessage.GetMessageDescription("E0004"), selectedAsyncTask.TaskId)); } else { // Asynchronous task exceeds maximum number of retries // Update task as abort string exceptionInfo = "ErrorMessageID: " + asyncReturnValue.ErrorMessageID + Environment.NewLine + "ErrorMessage: " + asyncReturnValue.ErrorMessage; this.UpdateAsyncTask(selectedAsyncTask, AsyncTaskUpdate.FAIL, exceptionInfo); LogIF.ErrorLog("ASYNC-SERVICE", string.Format(GetMessage.GetMessageDescription("E0005"), selectedAsyncTask.TaskId)); } } } else { // Selected Asynchronous task is completed successfully. this.UpdateAsyncTask(selectedAsyncTask, AsyncTaskUpdate.SUCCESS); LogIF.InfoLog("ASYNC-SERVICE", string.Format(GetMessage.GetMessageDescription("I0003"), selectedAsyncTask.TaskId)); } } catch (BusinessSystemException ex) { // Asynchronous task is aborted due to BusinessSystemException sent by user program. string exceptionInfo = "ErrorMessageID: " + ex.messageID + Environment.NewLine + "ErrorMessage: " + ex.Message; this.UpdateAsyncTask(selectedAsyncTask, AsyncTaskUpdate.FAIL, exceptionInfo); LogIF.ErrorLog("ASYNC-SERVICE", string.Format(GetMessage.GetMessageDescription("E0006"), selectedAsyncTask.TaskId, ex.Message)); } catch (Exception ex) { // Asynchronous task is aborted due to unexpected exception. string exceptionInfo = "ErrorMessageID: " + ex.GetType().Name + Environment.NewLine + "ErrorMessage: " + ex.Message; this.UpdateAsyncTask(selectedAsyncTask, AsyncTaskUpdate.FAIL, exceptionInfo); LogIF.ErrorLog("ASYNC-SERVICE", string.Format(GetMessage.GetMessageDescription("E0006"), selectedAsyncTask.TaskId, ex.Message)); } finally { // Async task is over this._workerThreadCount--; } }
/// <summary> /// Maintains the Main thread of the Asynchronous Service /// </summary> public void MainThreadInvoke() { // Asynchronous service is started LogIF.InfoLog("ASYNC-SERVICE", GetMessage.GetMessageDescription("I0001")); // Infinte loop processing for selecting register task. while (this._infiniteLoop) { try { // Get asynchronous task from the database. AsyncProcessingServiceParameterValue asyncParameterValue = new AsyncProcessingServiceParameterValue("AsyncProcessingService", "SelectTask", "SelectTask", "SQL", new MyUserInfo("AsyncProcessingService", "AsyncProcessingService")); asyncParameterValue.RegistrationDateTime = DateTime.Now - new TimeSpan(_maxNumberOfHours, 0, 0); asyncParameterValue.NumberOfRetries = this._maxNumberOfRetries; asyncParameterValue.CompletionDateTime = DateTime.Now - new TimeSpan(_maxNumberOfHours, 0, 0); LayerB layerB = new LayerB(); AsyncProcessingServiceReturnValue selectedAsyncTask = (AsyncProcessingServiceReturnValue)layerB.DoBusinessLogic( (BaseParameterValue)asyncParameterValue, DbEnum.IsolationLevelEnum.ReadCommitted); // Existence check of asynchronous task if (string.IsNullOrEmpty(selectedAsyncTask.UserId)) { // Asynchronous task does not exist. // Wait for the asynchronous task to be registered in the database. Thread.Sleep(this._numberOfSeconds * 1000); // Continue to this infinite loop. continue; } // Asynchronous task exists. // Check the number of free worker threads. int freeWorkerThreads = 0; int completionPortThreads = 0; // Gets the available threads. ThreadPool.GetAvailableThreads(out freeWorkerThreads, out completionPortThreads); while (freeWorkerThreads == 0) { // Wait for the completion of the worker thread. Thread.Sleep(this._numberOfSeconds * 1000); // Get available threads. ThreadPool.GetAvailableThreads(out freeWorkerThreads, out completionPortThreads); } // Selected asynchronous task is assigned to a worker thread this.UpdateAsyncTask(selectedAsyncTask, AsyncTaskUpdate.START); LogIF.InfoLog("ASYNC-SERVICE", string.Format(GetMessage.GetMessageDescription("I0002"), selectedAsyncTask.TaskId)); // Assign the task to the worker thread ThreadPool.QueueUserWorkItem(new WaitCallback(this.WorkerThreadCallBack), (object)selectedAsyncTask); } catch (Exception ex) { // Service Failed due to unexpected exception. this._infiniteLoop = false; LogIF.ErrorLog("ASYNC-SERVICE", string.Format(GetMessage.GetMessageDescription("E0000"), ex.Message.ToString())); } } }
/// <summary> /// Resumes asynchronous process in the middle of the processing. /// </summary> /// <param name="taskID">Task ID</param> /// <param name="userReturnValue">asynchronous return value</param> private void ResumeProcessing(int taskID, AsyncProcessingServiceReturnValue userReturnValue) { // Reset the command of selected task. this.UpdateTaskCommand(taskID, 0, userReturnValue); }