Commit d467c6d88506d48fb0c8e3af2dd76d107b522de1
1 parent
4ba41afb
Exists in
dev
Optimisation log_agent_status() (ex update_survey())
+ bugfix import celme + activity diag
Showing
5 changed files
with
101 additions
and
37 deletions
Show diff stats
README.md
@@ -73,9 +73,7 @@ Author: E. Pallier | @@ -73,9 +73,7 @@ Author: E. Pallier | ||
73 | 73 | ||
74 | VERSION: 0.20.31 | 74 | VERSION: 0.20.31 |
75 | 75 | ||
76 | -Comment: AgentM | ||
77 | - | ||
78 | - - routine_process() : envoi commande n'est plus bloquant | 76 | +Comment: Optimisation log_agent_status() (ex update_survey()) |
79 | 77 | ||
80 | - Scenario de test : | 78 | - Scenario de test : |
81 | - lancer agents A et B en mode simu (option -t): ./pyros.py -t start agentA,agentB | 79 | - lancer agents A et B en mode simu (option -t): ./pyros.py -t start agentA,agentB |
@@ -89,7 +87,9 @@ Comment: AgentM | @@ -89,7 +87,9 @@ Comment: AgentM | ||
89 | (ou encore: activer l'environnement virtuel, puis lancer "cd src/agent/ ; ./AgentA.py configfile") | 87 | (ou encore: activer l'environnement virtuel, puis lancer "cd src/agent/ ; ./AgentA.py configfile") |
90 | - pour utiliser thread ou processus : il suffit de mettre la constante RUN_IN_THREAD de AgentA (ou AgentB ou AgentX) à False ou True | 88 | - pour utiliser thread ou processus : il suffit de mettre la constante RUN_IN_THREAD de AgentA (ou AgentB ou AgentX) à False ou True |
91 | 89 | ||
92 | - - Autres remarques: | 90 | + - Historique des nouveautés : |
91 | + - AgentM (début) pour remplacer progressivement l'agent monitoring | ||
92 | + - routine_process() : envoi commande n'est plus bloquant | ||
93 | - pyros.py peut lancer plusieurs agents (A et B) en même temps | 93 | - pyros.py peut lancer plusieurs agents (A et B) en même temps |
94 | - run(N) : run only N iterations | 94 | - run(N) : run only N iterations |
95 | - send_command() implemented | 95 | - send_command() implemented |
src/agent/Agent.py
@@ -72,12 +72,12 @@ print() | @@ -72,12 +72,12 @@ print() | ||
72 | 72 | ||
73 | # --- GENERAL PURPOSE IMPORT --- | 73 | # --- GENERAL PURPOSE IMPORT --- |
74 | #from __future__ import absolute_import | 74 | #from __future__ import absolute_import |
75 | +import utils.Logger as L | ||
75 | import platform | 76 | import platform |
76 | import random | 77 | import random |
77 | from threading import Thread | 78 | from threading import Thread |
78 | import threading, multiprocessing | 79 | import threading, multiprocessing |
79 | import time | 80 | import time |
80 | -import utils.Logger as L | ||
81 | import socket | 81 | import socket |
82 | #import ctypes | 82 | #import ctypes |
83 | #import copy | 83 | #import copy |
@@ -185,19 +185,82 @@ class StoppableThreadEvenWhenSleeping(threading.Thread): | @@ -185,19 +185,82 @@ class StoppableThreadEvenWhenSleeping(threading.Thread): | ||
185 | class Agent: | 185 | class Agent: |
186 | """ | 186 | """ |
187 | Behavior of an agent: | 187 | Behavior of an agent: |
188 | + - If idle : | ||
189 | + - still does routine_process() and general_process() | ||
190 | + - does not do specific_process() | ||
188 | - Once a command has been sent to another agent : | 191 | - Once a command has been sent to another agent : |
189 | - - It waits for the end of execution of the command and get its result | ||
190 | - - If command is timed out or has been skipped or killed, then same command will be re-executed at next iteration | ||
191 | - - Then only, it goes to next iteration | 192 | + - It waits (non blocking) for the end of execution of the command and get its result |
193 | + - If command is timed out or has been skipped or killed, then it is NOT re-executed at next iteration (except if needed explicitely) | ||
192 | """ | 194 | """ |
193 | 195 | ||
196 | + """ | ||
197 | + PLANTUML ACTIVITY DIAGRAM | ||
198 | + # (http://plantuml.com/fr/activity-diagram-legacy) | ||
199 | + """ | ||
200 | + | ||
201 | + """ | ||
202 | + @startuml | ||
203 | + version | ||
204 | + @enduml | ||
205 | + """ | ||
206 | + | ||
207 | + """ | ||
208 | + @startuml | ||
209 | + | ||
210 | + title | ||
211 | + __** Agent.run() function activity diagram **__ | ||
212 | + end title | ||
213 | + | ||
214 | + skinparam activity { | ||
215 | + StartColor red | ||
216 | + EndColor Silver | ||
217 | + BackgroundColor Peru | ||
218 | + BackgroundColor<< Begin >> Olive | ||
219 | + BorderColor Peru | ||
220 | + FontName Impact | ||
221 | + } | ||
222 | + | ||
223 | + (*) --> load_config() | ||
224 | + | ||
225 | + --> init() | ||
226 | + | ||
227 | + partition infinite_loop { | ||
228 | + ---> "reload_config()" | ||
229 | + note right | ||
230 | + only if changed | ||
231 | + end note | ||
232 | + | ||
233 | + --> log_agent_status() | ||
234 | + note right | ||
235 | + Log this agent status in DB | ||
236 | + end note | ||
237 | + | ||
238 | + --> routine_process() | ||
239 | + | ||
240 | + --> cmd = get_next_valid_command() | ||
241 | + --> cmd = command_process(cmd) | ||
242 | + note right | ||
243 | + only if there is a command | ||
244 | + end note | ||
245 | + } | ||
246 | + | ||
247 | + If "NEW ITERATION ?" then | ||
248 | + --> [Yes] "reload_config()" | ||
249 | + else | ||
250 | + --> (*) | ||
251 | + Endif | ||
252 | + | ||
253 | + @enduml | ||
254 | + """ | ||
255 | + | ||
256 | + | ||
194 | 257 | ||
195 | # Maximum duration of this agent (only for SIMULATION mode) | 258 | # Maximum duration of this agent (only for SIMULATION mode) |
196 | # If set to None, it will never exit except if asked (or CTRL-C) | 259 | # If set to None, it will never exit except if asked (or CTRL-C) |
197 | # If set to 20, it will exit after 20s | 260 | # If set to 20, it will exit after 20s |
198 | SIMULATOR_MAX_DURATION_SEC = None | 261 | SIMULATOR_MAX_DURATION_SEC = None |
199 | #SIMULATOR_MAX_DURATION_SEC = 30 | 262 | #SIMULATOR_MAX_DURATION_SEC = 30 |
200 | - | 263 | + |
201 | # FOR TEST ONLY | 264 | # FOR TEST ONLY |
202 | # Run this agent in simulator mode | 265 | # Run this agent in simulator mode |
203 | SIMULATOR_MODE = True | 266 | SIMULATOR_MODE = True |
@@ -345,10 +408,10 @@ class Agent: | @@ -345,10 +408,10 @@ class Agent: | ||
345 | self.RUN_IN_THREAD = RUN_IN_THREAD | 408 | self.RUN_IN_THREAD = RUN_IN_THREAD |
346 | self.set_status(self.STATUS_LAUNCH) | 409 | self.set_status(self.STATUS_LAUNCH) |
347 | self.set_idle() | 410 | self.set_idle() |
348 | - | 411 | + |
349 | self._log = LogPyros() | 412 | self._log = LogPyros() |
350 | self._log.set_agent_alias(self.name) | 413 | self._log.set_agent_alias(self.name) |
351 | - | 414 | + |
352 | #self.set_mode(self.MODE_IDLE) | 415 | #self.set_mode(self.MODE_IDLE) |
353 | if not config_filename: | 416 | if not config_filename: |
354 | config_filename = self.DEFAULT_CONFIG_FILE_NAME | 417 | config_filename = self.DEFAULT_CONFIG_FILE_NAME |
@@ -379,11 +442,11 @@ class Agent: | @@ -379,11 +442,11 @@ class Agent: | ||
379 | #if len(tmp) == 0: | 442 | #if len(tmp) == 0: |
380 | #nb_agents = AgentSurvey.objects.filter(name=self.name).count() | 443 | #nb_agents = AgentSurvey.objects.filter(name=self.name).count() |
381 | #if nb_agents == 0: | 444 | #if nb_agents == 0: |
382 | - if not AgentSurvey.objects.filter(name=self.name).exists(): | 445 | + if AgentSurvey.objects.filter(name=self.name).exists(): |
446 | + self._agent_survey = AgentSurvey.objects.get(name=self.name) | ||
447 | + else: | ||
383 | self._agent_survey = AgentSurvey.objects.create(name=self.name, validity_duration_sec=60, mode=self.mode, status=self.status) | 448 | self._agent_survey = AgentSurvey.objects.create(name=self.name, validity_duration_sec=60, mode=self.mode, status=self.status) |
384 | - self.printd("Agent survey is", self._agent_survey) | ||
385 | - #self._agent_survey = AgentSurvey(name=self.name, validity_duration_sec=60, mode=self.mode, status=self.status) | ||
386 | - #self._agent_survey.save() | 449 | + self.printd("Agent survey is", self._agent_survey) |
387 | 450 | ||
388 | def __repr__(self): | 451 | def __repr__(self): |
389 | return "I am agent " + self.name | 452 | return "I am agent " + self.name |
@@ -417,7 +480,7 @@ class Agent: | @@ -417,7 +480,7 @@ class Agent: | ||
417 | """ | 480 | """ |
418 | 481 | ||
419 | self.load_config() | 482 | self.load_config() |
420 | - | 483 | + |
421 | if self.SIMULATOR_MODE: | 484 | if self.SIMULATOR_MODE: |
422 | self._log.print("[IN SIMULATOR MODE]") | 485 | self._log.print("[IN SIMULATOR MODE]") |
423 | else: | 486 | else: |
@@ -440,11 +503,6 @@ class Agent: | @@ -440,11 +503,6 @@ class Agent: | ||
440 | Command.delete_pending_commands_for_agent(self.name) | 503 | Command.delete_pending_commands_for_agent(self.name) |
441 | 504 | ||
442 | ''' | 505 | ''' |
443 | - self.printd() | ||
444 | - self.printd(self) | ||
445 | - self.printd("FOR REAL ?", self.FOR_REAL) | ||
446 | - self.printd("DB3 used is:", djangosettings.DATABASES["default"]["NAME"]) | ||
447 | - | ||
448 | # SETUP | 506 | # SETUP |
449 | try: | 507 | try: |
450 | self.config = get_object_or_404(Config, id=1) | 508 | self.config = get_object_or_404(Config, id=1) |
@@ -467,7 +525,7 @@ class Agent: | @@ -467,7 +525,7 @@ class Agent: | ||
467 | 525 | ||
468 | # Bad number of iterations, so exit | 526 | # Bad number of iterations, so exit |
469 | if nb_iter is not None: | 527 | if nb_iter is not None: |
470 | - if nb_iter <= 0: break | 528 | + if nb_iter <= 0: break |
471 | # Number of iterations asked is reached, so exit | 529 | # Number of iterations asked is reached, so exit |
472 | if self._iter_num > nb_iter: | 530 | if self._iter_num > nb_iter: |
473 | print(f"Exit because number of iterations asked ({nb_iter}) has been reached") | 531 | print(f"Exit because number of iterations asked ({nb_iter}) has been reached") |
@@ -488,8 +546,8 @@ class Agent: | @@ -488,8 +546,8 @@ class Agent: | ||
488 | 546 | ||
489 | self.load_config() # only if changed | 547 | self.load_config() # only if changed |
490 | 548 | ||
491 | - # Update my current mode and status in DB | ||
492 | - self.update_survey() | 549 | + # Log this agent status (update my current mode and status in DB) |
550 | + self.log_agent_status() | ||
493 | 551 | ||
494 | self.printd("------START COMMMAND PROCESSING------") | 552 | self.printd("------START COMMMAND PROCESSING------") |
495 | 553 | ||
@@ -500,18 +558,17 @@ class Agent: | @@ -500,18 +558,17 @@ class Agent: | ||
500 | #Command.purge_old_commands_for_agent(self.name) | 558 | #Command.purge_old_commands_for_agent(self.name) |
501 | self.purge_old_commands_sent_to_me() | 559 | self.purge_old_commands_sent_to_me() |
502 | 560 | ||
561 | + # ROUTINE process | ||
562 | + #if self.is_active(): | ||
563 | + self.routine_process() | ||
564 | + #self.printd("I am IDLE, so I bypass the routine_process (do not send any new command)") | ||
565 | + | ||
503 | # Get next command to execute | 566 | # Get next command to execute |
504 | cmd = self.get_next_valid_command() | 567 | cmd = self.get_next_valid_command() |
505 | #if cmd: cmd = self.general_process(cmd) | 568 | #if cmd: cmd = self.general_process(cmd) |
506 | - | ||
507 | # Process this (next) command (if exists) | 569 | # Process this (next) command (if exists) |
508 | if cmd: cmd = self.command_process(cmd) | 570 | if cmd: cmd = self.command_process(cmd) |
509 | 571 | ||
510 | - # ROUTINE process | ||
511 | - #if self.is_active(): | ||
512 | - self.routine_process() | ||
513 | - #self.printd("I am IDLE, so I bypass the routine_process (do not send any new command)") | ||
514 | - | ||
515 | self.printd("------END COMMMAND PROCESSING------") | 572 | self.printd("------END COMMMAND PROCESSING------") |
516 | 573 | ||
517 | #self.waitfor(self.mainloop_waittime) | 574 | #self.waitfor(self.mainloop_waittime) |
@@ -519,7 +576,7 @@ class Agent: | @@ -519,7 +576,7 @@ class Agent: | ||
519 | self.print("-"*20, "MAIN LOOP ITERATION (END)", "-"*20) | 576 | self.print("-"*20, "MAIN LOOP ITERATION (END)", "-"*20) |
520 | #self.do_log(LOG_DEBUG, "Ending main loop iteration") | 577 | #self.do_log(LOG_DEBUG, "Ending main loop iteration") |
521 | 578 | ||
522 | - # Exit if max duration is reached | 579 | + # (simulator only) Exit if max duration is reached |
523 | if self.SIMULATOR_MAX_DURATION_SEC and (time.time()-start_time > self.SIMULATOR_MAX_DURATION_SEC): | 580 | if self.SIMULATOR_MAX_DURATION_SEC and (time.time()-start_time > self.SIMULATOR_MAX_DURATION_SEC): |
524 | self.print("Exit because of max duration set to ", self.SIMULATOR_MAX_DURATION_SEC, "s") | 581 | self.print("Exit because of max duration set to ", self.SIMULATOR_MAX_DURATION_SEC, "s") |
525 | self.kill_running_specific_cmd_if_exists() | 582 | self.kill_running_specific_cmd_if_exists() |
@@ -782,15 +839,21 @@ class Agent: | @@ -782,15 +839,21 @@ class Agent: | ||
782 | self._log.set_home(home) | 839 | self._log.set_home(home) |
783 | 840 | ||
784 | 841 | ||
785 | - def update_survey(self): | ||
786 | - self.printd("Updating the survey database table...") | 842 | + #def update_survey(self): |
843 | + def log_agent_status(self): | ||
844 | + """ | ||
845 | + Save (update) this agent current mode and status in DB | ||
846 | + """ | ||
847 | + self.printd("Updating the agent survey database table...") | ||
787 | #self.printd("- fetching table line for agent", self.name) | 848 | #self.printd("- fetching table line for agent", self.name) |
788 | # only necessary when using process (not necessary with threads) | 849 | # only necessary when using process (not necessary with threads) |
789 | #with transaction.atomic(): | 850 | #with transaction.atomic(): |
790 | - self._agent_survey = AgentSurvey.objects.get(name=self.name) | 851 | + #self._agent_survey = AgentSurvey.objects.get(name=self.name) |
791 | self._agent_survey.mode = self.mode | 852 | self._agent_survey.mode = self.mode |
792 | self._agent_survey.status = self.status | 853 | self._agent_survey.status = self.status |
793 | - self._agent_survey.save() | 854 | + #self._agent_survey.save() |
855 | + self._agent_survey.save(update_fields=["mode", "status"]) | ||
856 | + | ||
794 | 857 | ||
795 | """ | 858 | """ |
796 | def send_command(self, cmd_name): | 859 | def send_command(self, cmd_name): |
src/agent/AgentA.py
@@ -69,6 +69,7 @@ class AgentA(Agent): | @@ -69,6 +69,7 @@ class AgentA(Agent): | ||
69 | def __init__(self, name:str=None, config_filename=None, RUN_IN_THREAD=True): | 69 | def __init__(self, name:str=None, config_filename=None, RUN_IN_THREAD=True): |
70 | if name is None: name = self.__class__.__name__ | 70 | if name is None: name = self.__class__.__name__ |
71 | super().__init__(name, config_filename, RUN_IN_THREAD) | 71 | super().__init__(name, config_filename, RUN_IN_THREAD) |
72 | + self._log.print(f"init done for {name}") | ||
72 | 73 | ||
73 | # @override | 74 | # @override |
74 | def init(self): | 75 | def init(self): |
39.4 KB
src/agent/logpyros.py
@@ -9,8 +9,8 @@ py_pwd = os.getcwd() + "/../utils" | @@ -9,8 +9,8 @@ py_pwd = os.getcwd() + "/../utils" | ||
9 | if (py_pwd not in py_path): | 9 | if (py_pwd not in py_path): |
10 | (os.sys.path).append(py_pwd) | 10 | (os.sys.path).append(py_pwd) |
11 | 11 | ||
12 | -#import utils.celme as celme | ||
13 | -import celme | 12 | +import utils.celme as celme |
13 | +#import celme | ||
14 | 14 | ||
15 | class LogPyros: | 15 | class LogPyros: |
16 | 16 |