فهرست منبع

System monitoring added

Implements ProxyProcess feature
Dalibor Votruba 4 سال پیش
والد
کامیت
7ec568fbcc

+ 15 - 0
Common/qdr.fnd.core/Json/Binder.cs

@@ -5,6 +5,7 @@ using System.Linq;
 using System.Reflection;
 using System.Text.Json;
 using System.Text.Json.Serialization;
+using System.Threading.Tasks;
 
 namespace Quadarax.Foundation.Core.Json
 {
@@ -162,6 +163,20 @@ namespace Quadarax.Foundation.Core.Json
             }
         }
 
+        public async Task SaveAsync<TObject>(string fileName, TObject bindingObject)
+        {
+            if (string.IsNullOrEmpty(fileName))
+                throw new ArgumentNullException(nameof(fileName));
+            if (bindingObject==null)
+                throw new ArgumentNullException(nameof(bindingObject));
+
+            await using (var writer = _fileSystem.File.Create(fileName))
+            {
+                await JsonSerializer.SerializeAsync(writer, bindingObject, SerializerOptions);
+                await writer.FlushAsync();
+            }
+        }
+
         public string SaveToString<TObject>(TObject bindingObject)
         {
             if (bindingObject==null)

+ 21 - 0
Common/qdr.fnd.core/Value/Extensions/RandomExt.cs

@@ -0,0 +1,21 @@
+using System;
+
+namespace Quadarax.Foundation.Core.Value.Extensions
+{
+    public static class RandomExt
+    {
+        public static bool NextBool(this Random owner, int truePercentage)
+        {
+            if (owner == null)
+                throw new ArgumentNullException(nameof(owner));
+            if (truePercentage == 0)
+                return false;
+            if (truePercentage >= 100)
+                return true;
+
+            var value = owner.Next(0, 100);
+            return value <= truePercentage;
+        }
+
+    }
+}

+ 1 - 1
ProcessServer/Business/Pool.cs

@@ -190,7 +190,7 @@ namespace BO.ProcessServer.Business
         {
             if (string.IsNullOrEmpty(path))
                 return path;
-            return path.Replace("{CD}", _fileSystem.Directory.GetCurrentDirectory());
+            return path.Replace(Constants.CS_TAG_CURRENT_DIR, _fileSystem.Directory.GetCurrentDirectory());
         }
 
         private string TranslateFileName(long documentId, string originalFileName)

+ 29 - 1
ProcessServer/Business/Scenarios/Scenarios.cs

@@ -1,10 +1,11 @@
 using System;
-using System.Diagnostics;
+using System.Collections.Generic;
 using System.Linq;
 using BO.AppServer.Metadata.Dto;
 using BO.ProcessServer.Business.Enums;
 using BO.ProcessServer.Options;
 using Quadarax.Foundation.Core.Logging;
+using Quadarax.Foundation.Core.Value.Extensions;
 
 
 namespace BO.ProcessServer.Business.Scenarios
@@ -13,12 +14,14 @@ namespace BO.ProcessServer.Business.Scenarios
     {
         private Configuration _configuration;
         private ILog _log;
+        private Random _rnd;
 
         public Scenarios(Configuration configuration, ILogger logger)
         {
             if (logger == null) throw new ArgumentNullException(nameof(logger));
             _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
             _log = logger.GetLogger(GetType());
+            _rnd = new Random();
         }
         
         public bool ExistsScenario(DocumentRDto docInfo)
@@ -29,12 +32,37 @@ namespace BO.ProcessServer.Business.Scenarios
 
         public Configuration.CfgScenario FindScenario(DocumentRDto docInfo)
         {
+            if (_configuration.System.Mode == AppModeEnum.Proxy ||
+                _configuration.System.Mode == AppModeEnum.ProxyProcess)
+            {
+                var succ = _rnd.NextBool(Constants.CS_DEF_PROXY_SCENARIO_SUCC_PCT);
+                return new Configuration.CfgScenario()
+                {
+
+                    Name = succ ? "DummySucc" : "DummyFail",
+                    AcceptFilters = new List<Configuration.CfgScenarioAcceptFilter>(),
+                    AcceptFiltersIfAll = true,
+                    ExitCodeFail = 1,
+                    ExitCodeSucc = 0,
+                    RunHidden = true,
+                    RunWindowsStyleRaw = "Minimized",
+                    ShellCommand = succ ? Constants.CS_DEF_SCENARIO_SUCC : Constants.CS_DEF_SCENARIO_FAIL,
+                    ShellCommandArguments =  Constants.CS_TAG_P_OUT_EXT + " " + Constants.CS_TAG_INPUT_FILES,
+                    TimeoutIntervalRaw = "00:00:10"
+                };
+            }
             return _configuration.System.Scenarios.FirstOrDefault(x => MatchScenario(x, docInfo));
         }
 
 
         private bool MatchScenario(Configuration.CfgScenario scenario, DocumentRDto document)
         {
+            if (_configuration.System.Mode == AppModeEnum.Proxy ||
+                _configuration.System.Mode == AppModeEnum.ProxyProcess)
+            {
+                return true;
+            }
+
 
             var match = scenario.AcceptFiltersIfAll;
             foreach (var filter in scenario.AcceptFilters)

+ 6 - 0
ProcessServer/Business/Workers/Contexts/ProcessingDocumentsCtx.cs

@@ -4,6 +4,7 @@ using System.IO.Abstractions;
 using BO.ProcessServer.Business.StatisticCounters;
 using BO.ProcessServer.Options;
 using Connector.PS;
+using Quadarax.Foundation.Core.Json;
 
 namespace BO.ProcessServer.Business.Workers.Contexts
 {
@@ -14,12 +15,17 @@ namespace BO.ProcessServer.Business.Workers.Contexts
         public IConnectionPS Connection { get; set; }
         public IFileSystem FileSystem { get; set; }
 
+        public DateTime LastMonitorStatusWrite { get; set; }
+        public Binder Binder { get; }
+
 
         public ProcessingDocumentsCtx(Configuration configuration,IList<SingleDocumentCalculationWorker> processes,IConnectionPS connection, IFileSystem fileSystem, Statistics statistics, Pool pool) : base(configuration, statistics, pool)
         {
             Processes = processes ?? throw new ArgumentNullException(nameof(processes));
             Connection = connection ?? throw new ArgumentNullException(nameof(connection));
             FileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
+            LastMonitorStatusWrite = DateTime.Now;
+            Binder = new Binder(FileSystem);
         }
     }
 }

+ 24 - 1
ProcessServer/Business/Workers/ProcessingDocumentsWorker.cs

@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using System.IO.Abstractions;
 using System.Linq;
 using System.Threading.Tasks;
@@ -40,6 +41,8 @@ namespace BO.ProcessServer.Business.Workers
             // ensure connection
             if (!ctx.Connection.IsOpen)
                 ctx.Connection.Open(ctx.Configuration.ApiUser, ctx.Configuration.ApiUserPwd, ctx.Configuration.ApiMagic);
+            
+            await SaveProcessesState(ctx);
 
             while (ctx.Processes.Count(x => x.Status == ServerProcessStateEnum.Pending) <
                    ctx.Configuration.System.ScenarioParallelThreads)
@@ -60,5 +63,25 @@ namespace BO.ProcessServer.Business.Workers
                 }
             }
         }
+
+        private async Task SaveProcessesState(ProcessingDocumentsCtx ctx)
+        {
+            if (ctx.Configuration.System.Status.Enabled)
+            {
+                if (DateTime.Now - ctx.LastMonitorStatusWrite > ctx.Configuration.System.Status.Interval)
+                {
+                    await ctx.Binder.SaveAsync(TranslatePath(ctx.FileSystem, ctx.Configuration.System.Status.File), ctx.Processes);
+                    ctx.LastMonitorStatusWrite = DateTime.Now;
+                }
+            }
+        }
+
+        private string TranslatePath(IFileSystem fs, string path)
+        {
+            if (string.IsNullOrEmpty(path))
+                return path;
+            return path.Replace(Constants.CS_TAG_CURRENT_DIR, fs.Directory.GetCurrentDirectory());
+        }
+
     }
 }

+ 35 - 17
ProcessServer/Business/Workers/SingleDocumentCalculationWorker.cs

@@ -69,33 +69,51 @@ namespace BO.ProcessServer.Business.Workers
                 processInfo.FileName = scenario.ShellCommand;
                 processInfo.WindowStyle = scenario.RunWindowsStyle;
                 processInfo.WorkingDirectory = ctx.Configuration.System.ScenarioPathBase;
-                processInfo.Arguments = TranslateArguments(scenario.ShellCommandArguments, ctx.InputFiles, document.PresetProcessProfile,document.PresetQuality, document.PresetWatermark,document.PresetTest);
+                processInfo.Arguments = TranslateArguments(scenario.ShellCommandArguments, ctx.InputFiles,
+                    document.PresetProcessProfile, document.PresetQuality, document.PresetWatermark,
+                    document.PresetTest);
+                processInfo.RedirectStandardOutput = true;
+                processInfo.RedirectStandardError = true;
                 ShellCommand = processInfo.FileName + " " + processInfo.Arguments;
-                ctx.Process = Process.Start(processInfo);
-                Log(LogSeverityEnum.Info, $"Starting process '{Name}.{ctx.Process?.ProcessName}' [Id:{ctx.Process?.Id}]: {ShellCommand}");
-                if (ctx.Process != null)
-                {
-                    ctx.Process.WaitForExit();
-                    Log(LogSeverityEnum.Info, $"End process '{Name}.{ctx.Process?.ProcessName}' [Id:{ctx.Process?.Id}]: Exit code {ctx.Process.ExitCode}");
 
-                    if (ctx.Process.ExitCode == scenario.ExitCodeSucc)
+                using (ctx.Process = Process.Start(processInfo))
+                {
+                    var errors = await ctx.Process.StandardError.ReadToEndAsync();
+                    var outputs = await ctx.Process.StandardOutput.ReadToEndAsync();
+                    Log(LogSeverityEnum.Info,
+                        $"Starting process '{Name}.{ctx.Process?.ProcessName}' [Id:{ctx.Process?.Id}]: {ShellCommand}");
+                    if (ctx.Process != null)
                     {
-                        Status = ServerProcessStateEnum.Done;
+                        ctx.Process.WaitForExit();
+                        if (!string.IsNullOrEmpty(errors))
+                            Log(LogSeverityEnum.Error, errors);
+                        if (!string.IsNullOrEmpty(outputs))
+                            Log(LogSeverityEnum.Info, outputs);
 
-                    }else if (ctx.Process.ExitCode == scenario.ExitCodeFail)
-                    {
-                        Status = ServerProcessStateEnum.FailExit;
+                        Log(LogSeverityEnum.Info,
+                            $"End process '{Name}.{ctx.Process?.ProcessName}' [Id:{ctx.Process?.Id}]: Exit code {ctx.Process.ExitCode}");
+
+                        if (ctx.Process.ExitCode == scenario.ExitCodeSucc)
+                        {
+                            Status = ServerProcessStateEnum.Done;
+
+                        }
+                        else if (ctx.Process.ExitCode == scenario.ExitCodeFail)
+                        {
+                            Status = ServerProcessStateEnum.FailExit;
+                        }
+                        else
+                        {
+                            Log(LogSeverityEnum.Warn,
+                                $"Process '{Name}.{ctx.Process?.ProcessName}' has unhandled exitcode {ctx.Process.ExitCode}! Goes to fail.");
+                            Status = ServerProcessStateEnum.FailInternal;
+                        }
                     }
                     else
                     {
-                        Log(LogSeverityEnum.Warn, $"Process '{Name}.{ctx.Process?.ProcessName}' has unhandled exitcode {ctx.Process.ExitCode}! Goes to fail.");
                         Status = ServerProcessStateEnum.FailInternal;
                     }
                 }
-                else
-                {
-                    Status = ServerProcessStateEnum.FailInternal;
-                }
             }
             Finished = DateTime.Now;
 

+ 4 - 0
ProcessServer/Constants.cs

@@ -7,6 +7,10 @@
         public const string CS_NLOG_CONFIGURATION_FILE = "processserver-nlog.config";
         public const string CS_LOG_LOGGER_LIFECYCLE = "Lifecycle";
 
+        public const string CS_DEF_SCENARIO_SUCC = "scenario-dummy.cmd";
+        public const string CS_DEF_SCENARIO_FAIL = "scenario-fail.cmd";
+        public const int CS_DEF_PROXY_SCENARIO_SUCC_PCT = 70;
+
 
         public const string CS_TAG_BEGIN = "{";
         public const string CS_TAG_END = "}";

+ 15 - 0
ProcessServer/Scenarios/scenario-dummy.cmd

@@ -1,3 +1,18 @@
 @echo off
 rem -- dummy scenario always returns OK
+setlocal enabledelayedexpansion
+
+rem put argument to array stored in argVec
+set argCount=0
+for %%x in (%*) do (
+   set /A argCount+=1
+   set "argVec[!argCount!]=%%~x"
+)
+
+echo Number of processed arguments: %argCount%
+
+rem foreach argVec (skip first) to copy files and add new file extension
+for /L %%i in (2,1,%argCount%) do copy /y "!argVec[%%i]!" "!argVec[%%i]!!argVec[1]!"
+
+
 exit 0