From 52942b3679d46375e1ccafff236d502b7ed2e705 Mon Sep 17 00:00:00 2001 From: Ivan Maslov Date: Sun, 9 Jan 2022 10:31:40 +0300 Subject: [PATCH] Test Managers.Process, fix some bugs --- .../Orchestrator/Managers/Process.py | 157 +++++++++++++----- Sources/pyOpenRPA/Orchestrator/Server.py | 5 +- .../Orchestrator/SettingsTemplate.py | 2 +- Sources/pyOpenRPA/Orchestrator/Web/Index.js | 2 +- .../pyOpenRPA/Orchestrator/Web/Index.xhtml | 20 ++- .../Orchestrator/__Orchestrator__.py | 6 +- 6 files changed, 135 insertions(+), 57 deletions(-) diff --git a/Sources/pyOpenRPA/Orchestrator/Managers/Process.py b/Sources/pyOpenRPA/Orchestrator/Managers/Process.py index c3e1273f..2e06c386 100644 --- a/Sources/pyOpenRPA/Orchestrator/Managers/Process.py +++ b/Sources/pyOpenRPA/Orchestrator/Managers/Process.py @@ -32,25 +32,31 @@ class Process(): self.mStartCMDStr = inStartCMDStr self.mProcessNameWOExeStr = inProcessNameWOExeStr self.mStopSafeTimeoutSecFloat = inStopSafeTimeoutSecFloat - __Orchestrator__.GSettingsGet()["ManagersProcessDict"][inProcessNameWOExeStr.upper()]=self - self.StatusCheck() - - def Manual2Auto(self): + __Orchestrator__.GSettingsGet()["ManagersProcessDict"][(inAgentHostNameStr.upper(), inAgentUserNameStr.upper(), inProcessNameWOExeStr.upper())]=self + lActivityDict = __Orchestrator__.ProcessorActivityItemCreate(inDef=self.StatusCheck,inArgList=[]) + __Orchestrator__.ProcessorActivityItemAppend(inActivityItemDict=lActivityDict) + def Manual2Auto(self) -> str: """ Remove Manual flag from process (if exists) - it will allow the schedule operations via def StatusCheckStart(self): def StatusCheckStorForce(self): def StatusCheckStopSafe(self): - :return: + :return: Process status. See self.mStatusStr. 0_STOPPED 1_STOPPED_MANUAL 2_STOP_SAFE 3_STOP_SAFE_MANUAL 4_STARTED 5_STARTED_MANUAL """ - if self.mStatusStr=="1_STOPPED_MANUAL": self.mStatusStr = "0_STOPPED" - if self.mStatusStr=="3_STOP_SAFE_MANUAL": self.mStatusStr = "2_STOP_SAFE" - if self.mStatusStr=="5_STARTED_MANUAL": self.mStatusStr = "4_STARTED" + lLogBool = False + if self.mStatusStr=="1_STOPPED_MANUAL": self.mStatusStr = "0_STOPPED"; lLogBool=True + if self.mStatusStr=="3_STOP_SAFE_MANUAL": self.mStatusStr = "2_STOP_SAFE"; lLogBool=True + if self.mStatusStr=="5_STARTED_MANUAL": self.mStatusStr = "4_STARTED"; lLogBool=True + # Log info about process + if lLogBool == True: + lL = __Orchestrator__.OrchestratorLoggerGet() + lL.info(f"Managers.Process: {self.mProcessNameWOExeStr} change status to {self.mStatusStr})") + return self.mStatusStr - def Start(self, inIsManualBool = True): + def Start(self, inIsManualBool = True) -> str: """ Manual/Auto start. Manual start will block scheduling execution. To return schedule execution use def Manual2Auto :param inIsManualBool: Default is True - Mark this operation as manual - StatusCheckStart/Stop will be blocked - only StatusCheck will be working. False - Auto operation - :return: + :return: Process status. See self.mStatusStr. 0_STOPPED 1_STOPPED_MANUAL 2_STOP_SAFE 3_STOP_SAFE_MANUAL 4_STARTED 5_STARTED_MANUAL """ # Send activity item to agent - wait result if self.mStartPathStr is not None: lCMDStr = f"start {os.path.abspath(self.mStartPathStr)}" @@ -71,8 +77,9 @@ class Process(): # Log info about process lL = __Orchestrator__.OrchestratorLoggerGet() lL.info(f"Managers.Process: {self.mProcessNameWOExeStr} change status to {self.mStatusStr})") + return self.mStatusStr - def StopSafe(self, inIsManualBool = True): + def StopSafe(self, inIsManualBool = True) -> str: """ Manual/Auto stop safe. Stop safe is the operation which send signal to process to terminate own work (send term signal to process). Managers.Process wait for the mStopSafeTimeoutSecFloat seconds. After that, if process is not terminated - self will StopForce it. Manual stop safe will block scheduling execution. To return schedule execution use def Manual2Auto @@ -82,13 +89,13 @@ class Process(): """ pass - def StopForce(self, inIsManualBool = True): + def StopForce(self, inIsManualBool = True) -> str: """ Manual/Auto stop force. Force stop dont wait process termination - it just terminate process now. Manual stop safe will block scheduling execution. To return schedule execution use def Manual2Auto :param inIsManualBool: Default is True - Mark this operation as manual - StatusCheckStart/Stop will be blocked - only StatusCheck will be working. False - Auto operation - :return: + :return: Process status. See self.mStatusStr. 0_STOPPED 1_STOPPED_MANUAL 2_STOP_SAFE 3_STOP_SAFE_MANUAL 4_STARTED 5_STARTED_MANUAL """ # Send activity item to agent - wait result lCMDStr = f'taskkill /im "{self.mProcessNameWOExeStr}.exe" /fi "username eq %USERNAME%"' @@ -105,7 +112,7 @@ class Process(): # Log info about process lL = __Orchestrator__.OrchestratorLoggerGet() lL.info(f"Managers.Process: {self.mProcessNameWOExeStr} change status to {self.mStatusStr})") - + return self.mStatusStr def RestartSafe(self, inIsManualBool = True): """ @@ -131,19 +138,26 @@ class Process(): """ Check if process is alive. The def will save the manual flag is exists. - :return: + :return: Process status. See self.mStatusStr. 0_STOPPED 1_STOPPED_MANUAL 2_STOP_SAFE 3_STOP_SAFE_MANUAL 4_STARTED 5_STARTED_MANUAL """ # Send activity item to agent - wait result + lLogBool = False lActivityItemUserProcessList = __Orchestrator__.ProcessorActivityItemCreate(inDef="ProcessWOExeUpperUserListGet") lGUIDStr = __Orchestrator__.AgentActivityItemAdd(inHostNameStr=self.mAgentHostNameStr,inUserStr=self.mAgentUserNameStr,inActivityItemDict=lActivityItemUserProcessList) lUserProcessList = __Orchestrator__.AgentActivityItemReturnGet(inGUIDStr=lGUIDStr) if self.mProcessNameWOExeStr.upper() in lUserProcessList: - if self.mStatusStr == "1_STOPPED_MANUAL": self.mStatusStr = "5_STARTED_MANUAL" - if self.mStatusStr == "0_STOPPED": self.mStatusStr = "4_STARTED" + if self.mStatusStr == "1_STOPPED_MANUAL": self.mStatusStr = "5_STARTED_MANUAL"; lLogBool=True + if self.mStatusStr == "0_STOPPED": self.mStatusStr = "4_STARTED"; lLogBool=True + if self.mStatusStr is None: self.mStatusStr = "4_STARTED"; lLogBool=True else: - if self.mStatusStr == "5_STARTED_MANUAL": self.mStatusStr = "1_STOPPED_MANUAL" - if self.mStatusStr == "4_STARTED": self.mStatusStr = "0_STOPPED" - + if self.mStatusStr == "5_STARTED_MANUAL": self.mStatusStr = "1_STOPPED_MANUAL"; lLogBool=True + if self.mStatusStr == "4_STARTED": self.mStatusStr = "0_STOPPED"; lLogBool=True + if self.mStatusStr is None: self.mStatusStr = "0_STOPPED"; lLogBool=True + # Log info about process + if lLogBool == True: + lL = __Orchestrator__.OrchestratorLoggerGet() + lL.info(f"Managers.Process: {self.mProcessNameWOExeStr} change status to {self.mStatusStr})") + return self.mStatusStr def StatusCheckStart(self): """ Check process status and run it if auto stopped self.mStatusStr is "0_STOPPED" @@ -177,21 +191,25 @@ class Process(): pass -def ProcessGet(inProcessNameWOExeStr: str) -> Process: +def ProcessGet(inAgentHostNameStr: str, inAgentUserNameStr: str, inProcessNameWOExeStr: str) -> Process: """ Return the process instance by the inProcessNameWOExeStr + :param inAgentHostNameStr: Agent hostname in any case. Required to identify Process + :param inAgentUserNameStr: Agent user name in any case. Required to identify Process :param inProcessNameWOExeStr: The process name without extension .exe (the key of the Process instance). Any case - will be processed to the upper case :return: Process instance (if exists) Else None """ - return __Orchestrator__.GSettingsGet()["ManagersProcessDict"].get(inProcessNameWOExeStr.upper(),None) + return __Orchestrator__.GSettingsGet()["ManagersProcessDict"].get((inAgentHostNameStr.upper(), inAgentUserNameStr.upper(), inProcessNameWOExeStr.upper()),None) -def ProcessStatusStrGet(inProcessNameWOExeStr): +def ProcessStatusStrGet(inAgentHostNameStr: str, inAgentUserNameStr: str, inProcessNameWOExeStr: str) -> str: """ Get the status of the Process instance. + :param inAgentHostNameStr: Agent hostname in any case. Required to identify Process + :param inAgentUserNameStr: Agent user name in any case. Required to identify Process :param inProcessNameWOExeStr: The process name without extension .exe (the key of the Process instance). Any case - will be processed to the upper case - :return: Str + :return: Process status. See self.mStatusStr. Process instance has the following statuses: - 0_STOPPED - 1_STOPPED_MANUAL @@ -201,68 +219,115 @@ def ProcessStatusStrGet(inProcessNameWOExeStr): - 5_STARTED_MANUAL - None (if Process instance not exists) """ - lProcess = ProcessGet(inProcessNameWOExeStr=inProcessNameWOExeStr) + lProcess = ProcessGet(inAgentHostNameStr = inAgentHostNameStr, inAgentUserNameStr = inAgentUserNameStr, inProcessNameWOExeStr=inProcessNameWOExeStr) if lProcess is not None: return lProcess.mStatusStr - else: return None -def ProcessStart(inProcessNameWOExeStr: str, inIsManualBool: bool = True) -> None: +def ProcessStart(inAgentHostNameStr: str, inAgentUserNameStr: str, inProcessNameWOExeStr: str, inIsManualBool: bool = True) -> str: """ Manual/Auto start. Manual start will block scheduling execution. To return schedule execution use def Manual2Auto + :param inAgentHostNameStr: Agent hostname in any case. Required to identify Process + :param inAgentUserNameStr: Agent user name in any case. Required to identify Process :param inProcessNameWOExeStr: The process name without extension .exe (the key of the Process instance). Any case - will be processed to the upper case :param inIsManualBool: Default is True - Mark this operation as manual - StatusCheckStart/Stop will be blocked - only StatusCheck will be working. False - Auto operation - :return: + :return: Process status. See self.mStatusStr. + Process instance has the following statuses: + - 0_STOPPED + - 1_STOPPED_MANUAL + - 2_STOP_SAFE + - 3_STOP_SAFE_MANUAL + - 4_STARTED + - 5_STARTED_MANUAL + - None (if Process instance not exists) """ - lProcess = ProcessGet(inProcessNameWOExeStr=inProcessNameWOExeStr) + lProcess = ProcessGet(inAgentHostNameStr = inAgentHostNameStr, inAgentUserNameStr = inAgentUserNameStr, inProcessNameWOExeStr=inProcessNameWOExeStr) if lProcess is not None: return lProcess.Start(inIsManualBool=inIsManualBool) - else: return None -def ProcessStopSafe(inProcessNameWOExeStr: str, inIsManualBool: bool = True) -> None: +def ProcessStopSafe(inAgentHostNameStr: str, inAgentUserNameStr: str, inProcessNameWOExeStr: str, inIsManualBool: bool = True) -> str: """ Manual/Auto stop safe. Stop safe is the operation which send signal to process to terminate own work (send term signal to process). Managers.Process wait for the mStopSafeTimeoutSecFloat seconds. After that, if process is not terminated - self will StopForce it. Manual stop safe will block scheduling execution. To return schedule execution use def Manual2Auto + :param inAgentHostNameStr: Agent hostname in any case. Required to identify Process + :param inAgentUserNameStr: Agent user name in any case. Required to identify Process :param inProcessNameWOExeStr: The process name without extension .exe (the key of the Process instance). Any case - will be processed to the upper case :param inIsManualBool: Default is True - Mark this operation as manual - StatusCheckStart/Stop will be blocked - only StatusCheck will be working. False - Auto operation - :return: + :return: Process status. See self.mStatusStr. + Process instance has the following statuses: + - 0_STOPPED + - 1_STOPPED_MANUAL + - 2_STOP_SAFE + - 3_STOP_SAFE_MANUAL + - 4_STARTED + - 5_STARTED_MANUAL + - None (if Process instance not exists) """ - lProcess = ProcessGet(inProcessNameWOExeStr=inProcessNameWOExeStr) + lProcess = ProcessGet(inAgentHostNameStr = inAgentHostNameStr, inAgentUserNameStr = inAgentUserNameStr, inProcessNameWOExeStr=inProcessNameWOExeStr) if lProcess is not None: return lProcess.StopSafe(inIsManualBool=inIsManualBool) - else: return None -def ProcessStopForce(inProcessNameWOExeStr: str, inIsManualBool: bool = True) -> None: +def ProcessStopForce(inAgentHostNameStr: str, inAgentUserNameStr: str, inProcessNameWOExeStr: str, inIsManualBool: bool = True) -> str: """ Manual/Auto stop force. Force stop dont wait process termination - it just terminate process now. Manual stop safe will block scheduling execution. To return schedule execution use def Manual2Auto + :param inAgentHostNameStr: Agent hostname in any case. Required to identify Process + :param inAgentUserNameStr: Agent user name in any case. Required to identify Process :param inProcessNameWOExeStr: The process name without extension .exe (the key of the Process instance). Any case - will be processed to the upper case :param inIsManualBool: Default is True - Mark this operation as manual - StatusCheckStart/Stop will be blocked - only StatusCheck will be working. False - Auto operation - :return: + :return: Process status. See self.mStatusStr. + Process instance has the following statuses: + - 0_STOPPED + - 1_STOPPED_MANUAL + - 2_STOP_SAFE + - 3_STOP_SAFE_MANUAL + - 4_STARTED + - 5_STARTED_MANUAL + - None (if Process instance not exists) """ - lProcess = ProcessGet(inProcessNameWOExeStr=inProcessNameWOExeStr) + lProcess = ProcessGet(inAgentHostNameStr = inAgentHostNameStr, inAgentUserNameStr = inAgentUserNameStr, inProcessNameWOExeStr=inProcessNameWOExeStr) if lProcess is not None: return lProcess.StopForce(inIsManualBool=inIsManualBool) - else: return None -def ProcessStatusCheck(inProcessNameWOExeStr: str) -> str: +def ProcessStatusCheck(inAgentHostNameStr: str, inAgentUserNameStr: str, inProcessNameWOExeStr: str) -> str: """ Check if process is alive. The def will save the manual flag is exists. + :param inAgentHostNameStr: Agent hostname in any case. Required to identify Process + :param inAgentUserNameStr: Agent user name in any case. Required to identify Process :param inProcessNameWOExeStr: The process name without extension .exe (the key of the Process instance). Any case - will be processed to the upper case - :return: str: Check process status and return it + :return: Process status. See self.mStatusStr. + Process instance has the following statuses: + - 0_STOPPED + - 1_STOPPED_MANUAL + - 2_STOP_SAFE + - 3_STOP_SAFE_MANUAL + - 4_STARTED + - 5_STARTED_MANUAL + - None (if Process instance not exists) """ - lProcess = ProcessGet(inProcessNameWOExeStr=inProcessNameWOExeStr) + lProcess = ProcessGet(inAgentHostNameStr=inAgentHostNameStr, inAgentUserNameStr=inAgentUserNameStr, + inProcessNameWOExeStr=inProcessNameWOExeStr) if lProcess is not None: lProcess.StatusCheck() return lProcess.mStatusStr - else: return None -def ProcessManual2Auto(inProcessNameWOExeStr: str) -> None: +def ProcessManual2Auto(inAgentHostNameStr: str, inAgentUserNameStr: str, inProcessNameWOExeStr: str) -> str: """ Remove Manual flag from process (if exists) - it will allow the schedule operations via def StatusCheckStart(self): def StatusCheckStorForce(self): def StatusCheckStopSafe(self): + :param inAgentHostNameStr: Agent hostname in any case. Required to identify Process + :param inAgentUserNameStr: Agent user name in any case. Required to identify Process :param inProcessNameWOExeStr: The process name without extension .exe (the key of the Process instance). Any case - will be processed to the upper case - :return: None + :return: Process status. See self.mStatusStr. + Process instance has the following statuses: + - 0_STOPPED + - 1_STOPPED_MANUAL + - 2_STOP_SAFE + - 3_STOP_SAFE_MANUAL + - 4_STARTED + - 5_STARTED_MANUAL + - None (if Process instance not exists) """ - lProcess = ProcessGet(inProcessNameWOExeStr=inProcessNameWOExeStr) - if lProcess is not None: lProcess.Manual2Auto() \ No newline at end of file + lProcess = ProcessGet(inAgentHostNameStr=inAgentHostNameStr, inAgentUserNameStr=inAgentUserNameStr, + inProcessNameWOExeStr=inProcessNameWOExeStr) + if lProcess is not None: return lProcess.Manual2Auto() \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/Server.py b/Sources/pyOpenRPA/Orchestrator/Server.py index 45eddc50..1b6b95a9 100644 --- a/Sources/pyOpenRPA/Orchestrator/Server.py +++ b/Sources/pyOpenRPA/Orchestrator/Server.py @@ -355,8 +355,9 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): self.end_headers() # Write content as utf-8 data self.wfile.write(inResponseDict["Body"]) - except ConnectionResetError as e: - if lL: lL.warning(f"An existing connection was forcibly closed by the remote host - OK for the network interactions (ConnectionResetError: [WinError 10054])") + except (ConnectionResetError, ConnectionAbortedError) as e: + if lL: lL.warning(f"SERVER: Connection was forcibly closed by the client side - OK for the network interactions (ConnectionResetError: [WinError 10054] or ConnectionAbortedError: [WinError 10053])") + def do_GET(self): try: self.OpenRPA = {} diff --git a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py index 3dd77b92..9a1a17fe 100644 --- a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py +++ b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py @@ -148,7 +148,7 @@ def __Create__(): # }, ], }, - "ManagersProcessDict":{}, # The key of the Process is mProcessNameWOExeStr.upper() + "ManagersProcessDict":{}, # The key of the Process is (mAgentHostNameStr.upper(), mAgentUserNameStr.upper(), mProcessNameWOExeStr.upper()) "ProcessorDict": { # Has been changed. New general processor (one threaded) v.1.2.0 "ActivityList": [ # List of the activities # { diff --git a/Sources/pyOpenRPA/Orchestrator/Web/Index.js b/Sources/pyOpenRPA/Orchestrator/Web/Index.js index 8dc6bc43..d53c7e86 100644 --- a/Sources/pyOpenRPA/Orchestrator/Web/Index.js +++ b/Sources/pyOpenRPA/Orchestrator/Web/Index.js @@ -970,7 +970,7 @@ $(document).ready(function() { { var lResponseJSON=JSON.parse(lData) console.log(lResponseJSON) - $(".mGlobal-pyOpenRPA-Debugging-Output")[0].value = lData + $(".mGlobal-pyOpenRPA-Debugging-Output")[0].value = JSON.stringify(lResponseJSON[0]) }, dataType: "text" }); diff --git a/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml b/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml index cab2739e..ec06ac11 100644 --- a/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml +++ b/Sources/pyOpenRPA/Orchestrator/Web/Index.xhtml @@ -45,6 +45,16 @@ margin: 5em 0em 0em; padding: 5em 0em; } + .ui.search.dropdown>input.search { + width:100%; + font-family:monospace; + font-weight: bold; + } + .ui.search.dropdown>.text { + width:100%; + font-family:monospace; + font-weight: bold; + } @@ -308,7 +318,7 @@
Def
diff --git a/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py b/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py index 752b839a..e3672f8d 100644 --- a/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py +++ b/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py @@ -2595,6 +2595,9 @@ def Orchestrator(inGSettings=None, inDumpRestoreBool = True, inRunAsAdministrato lAutocleanerThread.start() # Start the thread execution. if lL: lL.info("Autocleaner thread has been started") #Logging + # Set flag that orchestrator has been initialized + inGSettings["HiddenIsOrchestratorInitializedBool"] = True + # Orchestrator start activity if lL: lL.info("Orchestrator start activity run") #Logging for lActivityItem in gSettingsDict["OrchestratorStart"]["ActivityList"]: @@ -2616,8 +2619,7 @@ def Orchestrator(inGSettings=None, inDumpRestoreBool = True, inRunAsAdministrato gDaemonActivityLogDictRefreshSecInt = 10 # The second period for clear lDaemonActivityLogDict from old items gDaemonActivityLogDictLastTime = time.time() # The second perioad for clean lDaemonActivityLogDict from old items - # Set flag that orchestrator has been initialized - inGSettings["HiddenIsOrchestratorInitializedBool"] = True + while True: try: