public bool AddJobResultToCache(JobResult jobResult)
 {
     if (jobResult.jobSucceed == true)
     {
         string internalCacheKey = "JobResult:"+jobResult.job.GetCacheKey();
         return Redis.Instance.DB.StringSet(internalCacheKey, jobResult.resultString);
     }
     return false;
 }
        public bool OnJobCalcResult(JobResult jobResult)
        {
            //No retry for failed job. Retry should be occur only when node is unreachable

            JobStatus jobStatus = GetJobStatusByJobID(jobResult.job.jobID);
            //mark job status
            if (jobStatus != null)
            {
                if (jobStatus.jobStatusType != JobStatusType.CANCELED)
                    jobStatus.jobStatusType = JobStatusType.FINISHED;

            }
            else
            {
                Console.WriteLine(DateTime.Now.ToString("[HH:mm:ss.fff]") + "[Error][OnJobCalcResult] No job status found for jobID=" + jobResult.job.jobID);
                return false;
            }

            //notify node for job finish
            //When node is not alive, dont need to pass result to client
            Node node = nodeManager.GetNodeByNodeKey(jobResult.job.nodeKey);
            if (node != null)
            {
                node.WorkerFinish(jobResult.job.jobID);
            }
            else
            {
                Console.WriteLine(DateTime.Now.ToString("[HH:mm:ss.fff]") + "[Error][OnJobCalcResult] No node found for nodeKey=" + jobResult.job.nodeKey + ". Maybe logged out because of hearbeat.");
                return false;
            }
            ProcessWaitingJobQueue();

            bool ret = true;
            Client client = clientManager.GetClientByClientKey(jobResult.job.clientKey);
            if (client != null)
            {
                AsyncServerClientJobCalcResultCastMessage msg = new AsyncServerClientJobCalcResultCastMessage();
                msg.jobResult = jobResult;
                if (!client.GetAsyncComm().SendCast(msg))
                    Console.WriteLine("[Error] SendCast failed!");

                ret = true;
            }
            else
            {
                ret = false;
            }
            if (jobResult.resultString.Trim() == "")
            {
                string str = string.Format("JobCode\n{0}\n--------------------------\nParameter\n{1}\n--------------------------\n{2}\n--------------------------\n", jobResult.job.clientSideJobCode, jobResult.job.parameter, jobResult.resultString);
                //File.WriteAllText("empty_ressult.txt", str);
                File.AppendAllText("empty_ressult.txt", str);
            }
            //additionally add to cache
            jobResultCache.AddJobResultToCache(jobResult);

            return ret;
        }
        private bool ProcessJobWithCache(Job job)
        {
            string cacheKey = job.GetCacheKey();
            string resultString = jobResultCache.GetJobResultStringFromCache(cacheKey);
            if (resultString != null)
            {
                //cache hit
                JobResult jobResult = new JobResult();
                jobResult.job = job;
                jobResult.jobSucceed = true;
                jobResult.resultString = resultString;

                JobStatus jobStatus = GetJobStatusByJobID(job.jobID);
                //mark job status
                if (jobStatus != null)
                {
                    if (jobStatus.jobStatusType != JobStatusType.CANCELED)
                        jobStatus.jobStatusType = JobStatusType.FINISHED;
                }
                else
                {
                    Console.WriteLine(DateTime.Now.ToString("[HH:mm:ss.fff]") + "[Error][OnJobCalcResult] No job status found for jobID=" + job.jobID);
                }
                Client client = clientManager.GetClientByClientKey(jobResult.job.clientKey);
                if (client != null)
                {
                    AsyncServerClientJobCalcResultCastMessage castmsg = new AsyncServerClientJobCalcResultCastMessage();
                    castmsg.jobResult = jobResult;
                    Console.WriteLine("[ProcessJobWithCache] Send job result : " + jobResult.ToString());
                    if (!client.GetAsyncComm().SendCast(castmsg))
                        Console.WriteLine("[Error] SendCast failed!");
                }
                return true;
            }
            return false;
        }
        public override void RunJobProcessor(Job job)
        {
            int maxRunCount = 2;
            NativeMethods.SetErrorMode(NativeMethods.SetErrorMode(0) |
                               ErrorModes.SEM_NOGPFAULTERRORBOX |
                               ErrorModes.SEM_FAILCRITICALERRORS |
                               ErrorModes.SEM_NOOPENFILEERRORBOX);
            for (int runCount = 1; runCount <= maxRunCount && !jobProcessorManager.IsCanceledJob(job.jobID); runCount++)
            {
                if (runCount > 1)
                {
                    Console.WriteLine(DateTime.Now.ToString("[HH:mm:ss.fff]") + "[Error][JobProcessor] Task start failed. Retry next iteration " + runCount);
                    Thread.Sleep(1000);
                }
                //write file
                string inputFileName = jobProcessorManager.GetNextFilename() + "_" + job.jobID + ".trn";
                string outputFileName = inputFileName + ".res";

                string processorFullPath = Path.Combine(Environment.CurrentDirectory, processorRelativePath);
                string processorWorkingDirectory = Path.GetDirectoryName(processorFullPath);// Path.Combine(Path.GetDirectoryName(processorFullPath), "tmp");
                string IODirectory = Path.Combine(Path.GetDirectoryName(processorFullPath), "tmp");
                if (!Directory.Exists(IODirectory))
                {
                    DirectoryInfo di = Directory.CreateDirectory(IODirectory);
                }
                if (!Directory.Exists(processorWorkingDirectory))
                {
                    DirectoryInfo di = Directory.CreateDirectory(processorWorkingDirectory);
                }
                string inputFileFullPath = Path.Combine(IODirectory, inputFileName);
                string outputFileFullPath = Path.Combine(IODirectory, outputFileName);
                Process proc = null;
                try
                {
                    File.WriteAllText(inputFileFullPath, job.parameter, Encoding.ASCII);
                    File.Delete(outputFileFullPath);
                    string resultStr = null;
                    proc = jobProcessorManager.GetNewProcess(job);
                    
                    if (proc == null)
                    {
                        if (runCount == maxRunCount)
                        {
                            OnJobFailed(job);
                            return;
                        }
                        else
                        {
                            continue;
                        }
                    }
                    proc.StartInfo.FileName = processorFullPath;
                    proc.StartInfo.UseShellExecute = false;
                    proc.StartInfo.RedirectStandardOutput = true;
                    proc.StartInfo.Arguments = "\"" + inputFileFullPath + "\"";
                    proc.StartInfo.WorkingDirectory = processorWorkingDirectory;
                    proc.StartInfo.ErrorDialog = false;
                    
                    if (!proc.Start())
                    {
                        if (runCount == maxRunCount)
                        {
                            OnJobFailed(job);
                            return;
                        }
                        else
                        {
                            continue;
                        }
                    }
                    try
                    {
                        proc.PriorityClass = ProcessPriorityClass.BelowNormal;
                    }
                    catch (Exception)
                    {
                    }
                    bool succeed = false;

                    string line = "";
                    //starting status
                    {
                        JobStatus jobStatus = jobProcessorManager.GetNewJobStatus(job);
                        jobStatus.jobProgress = 0;
                        OnJobProgress(jobStatus, null);
                    }
                    StringBuilder buffer = new StringBuilder();
                    while (true)
                    {
                        bool lineEndFlag = false;
                        string currentBuffer;
                        int outChar = -1;
                        try
                        {
                            outChar = proc.StandardOutput.Read();

                            if (outChar == -1)
                            {
                                //stream closed
                                if (buffer.Length == 0)
                                    //if stream is empty, do nothing
                                    break;
                                else
                                {
                                    //if stream is not empty, process it!
                                    line = buffer.ToString();
                                    lineEndFlag = true;
                                }
                            }
                            else
                            {
                                buffer.Append((char)outChar);
                                currentBuffer = buffer.ToString();
                                if (currentBuffer.EndsWith("\r\n"))
                                {
                                    line = currentBuffer.Substring(0, currentBuffer.Length - 2);
                                    lineEndFlag = true;
                                }
                                else if (currentBuffer.EndsWith("\n"))
                                {
                                    line = currentBuffer.Substring(0, currentBuffer.Length - 1);
                                    lineEndFlag = true;
                                }
                            }
                        }
                        catch (IOException)
                        {
                            if (buffer.Length == 0)
                                //if stream is empty, do nothing
                                break;
                            else
                            {
                                //if stream is not empty, process it!
                                line = buffer.ToString();
                                lineEndFlag = true;
                            }
                        }
                        if (lineEndFlag == true)
                        {
                            line.Trim();
                            buffer.Clear();
                            //pattern : Progress/currentStep/totalStep (Progress/1/10)
                            if (line.StartsWith("Progress/"))
                            {
                                string[] strArr = line.Split('/');
                                if (strArr.Length == 3)
                                {
                                    int curr = int.Parse(strArr[1]);
                                    int total = int.Parse(strArr[2]);

                                    JobStatus jobStatus = jobProcessorManager.GetNewJobStatus(job);
                                    jobStatus.jobProgress = curr / total;
                                    if (OnJobProgress != null)
                                        OnJobProgress(jobStatus, null);
                                }
                            }
                        }
                        if (outChar == -1)
                            break;
                    }

                    //while ((line = proc.StandardOutput.ReadLine()) != null)
                    //{

                    //    //Console.WriteLine(DateTime.Now.ToString("[HH:mm:ss.fff]")+"[Job=" + job.jobID + "] " + line);
                    //    //pattern : Progress/currentStep/totalStep (Progress/1/10)
                    //    if (line.StartsWith("Progress/"))
                    //    {
                    //        string[] strArr = line.Split('/');
                    //        if (strArr.Length == 3)
                    //        {
                    //            int curr = int.Parse(strArr[1]);
                    //            int total = int.Parse(strArr[2]);

                    //            JobStatus jobStatus = jobProcessorManager.GetNewJobStatus(job);
                    //            jobStatus.jobProgress = curr / total;

                    //            OnJobProgress(jobStatus, null);
                    //        }
                    //    }
                    //}

                    proc.WaitForExit();

                    try
                    {
                        resultStr = File.ReadAllText(outputFileFullPath, Encoding.ASCII);
                    }
                    catch (Exception)
                    {
                        if (runCount == maxRunCount)
                        {
                            OnJobFailed(job);
                            return;
                        }
                        else
                        {
                            continue;
                        }
                    }

                    JobResult jobResult = new JobResult();
                    jobResult.job = job;
                    if (resultStr != null)
                    {
                        if (OnJobProgress != null)
                        {
                            JobStatus jobStatus = jobProcessorManager.GetNewJobStatus(job);
                            jobStatus.jobProgress = 1;
                            OnJobProgress(jobStatus, null);
                        }
                        jobResult.jobSucceed = succeed || proc.ExitCode == 0;
                        jobResult.resultString = "OK" + resultStr;
                        if (OnJobCompleted != null)
                        {
                            OnJobCompleted(jobResult, null);
                        }
                        return;
                    }
                    else
                    {
                        if (runCount == maxRunCount)
                        {
                            jobResult.jobSucceed = proc.ExitCode == 0;
                            OnJobCompleted(jobResult, null);
                            return;
                        }
                        else
                        {
                            continue;
                        }
                    }
                }
                catch (Exception e)
                {
                    if (proc != null)
                        proc.Close();
                    Console.WriteLine(DateTime.Now.ToString("[HH:mm:ss.fff]") + "[Error][JobProcessor] Task start failed." + e.ToString());
                    if (runCount == maxRunCount)
                    {
                        OnJobFailed(job);
                        return;
                    }
                    continue;
                }
            }
            if (jobProcessorManager.IsCanceledJob(job.jobID))
                OnJobFailed(job);
            return;
        }
        private void OnJobFailed(Job job)
        {
            JobResult jobResult = new JobResult();
            jobResult.job = job;
            jobResult.jobSucceed = false;
            jobResult.resultString = "OKfail";

            if (OnJobCompleted != null)
                OnJobCompleted(jobResult, null);
        }