Commit cf8b102563c3679ade40291a28e5a0c40864c01a
1 parent
03161a45
Exists in
dev
Implémenté la commande "restart_init"
(voir doc "play with a pyros agent" pour voir comment redémarrer un agent)
Showing
3 changed files
with
140 additions
and
112 deletions
Show diff stats
README.md
... | ... | @@ -73,7 +73,7 @@ Author: E. Pallier |
73 | 73 | |
74 | 74 | VERSION: 0.20.32 |
75 | 75 | |
76 | -Comment: Implémenté le "abort" dans le simulateur | |
76 | +Comment: Implémenté la commande "restart_init" (voir doc "play with a pyros agent") | |
77 | 77 | |
78 | 78 | - Scenario de test : |
79 | 79 | - lancer agents A et B en mode simu (option -t): ./pyros.py -t start agentA,agentB |
... | ... | @@ -87,7 +87,8 @@ Comment: Implémenté le "abort" dans le simulateur |
87 | 87 | (ou encore: activer l'environnement virtuel, puis lancer "cd src/agent/ ; ./AgentA.py configfile") |
88 | 88 | - pour utiliser thread ou processus : il suffit de mettre la constante RUN_IN_THREAD de AgentA (ou AgentB ou AgentX) à False ou True |
89 | 89 | |
90 | - - Historique des nouveautés : | |
90 | + - Historique des nouveautés implémentées : | |
91 | + - Implémenté le "abort" dans le simulateur | |
91 | 92 | - Optimisation log_agent_status() (ex update_survey()) |
92 | 93 | - AgentM (début) pour remplacer progressivement l'agent monitoring |
93 | 94 | - routine_process() : envoi commande n'est plus bloquant | ... | ... |
src/agent/Agent.py
... | ... | @@ -475,122 +475,140 @@ class Agent: |
475 | 475 | else: |
476 | 476 | time.sleep(nbsec) |
477 | 477 | |
478 | - def run(self, nb_iter=None, FOR_REAL: bool = True): | |
478 | + def run(self, nb_iter:int=None, FOR_REAL:bool=True): | |
479 | 479 | """ |
480 | 480 | FOR_REAL: set to False if you don't want Majordome to send commands to devices |
481 | 481 | """ |
482 | 482 | |
483 | - self.load_config() | |
483 | + self.DO_EXIT = False | |
484 | + self.DO_RESTART = True | |
484 | 485 | |
485 | - if self.SIMULATOR_MODE: | |
486 | - self._log.print("[IN SIMULATOR MODE]") | |
487 | - else: | |
488 | - self._log.print("[IN NORMAL MODE]") | |
489 | - self.SIMULATOR_MAX_DURATION_SEC=None | |
490 | - | |
491 | - start_time = time.time() | |
492 | - | |
493 | - self.FOR_REAL = FOR_REAL | |
494 | - | |
495 | - self.init() | |
486 | + # Will loop again only if DO_RESTART is True | |
487 | + while self.DO_RESTART: | |
488 | + self.DO_RESTART = False | |
496 | 489 | |
497 | - # Avoid blocking on false "running" commands | |
498 | - # (old commands that stayed with "running" status when agent was killed) | |
499 | - Command.delete_commands_with_running_status_for_agent(self.name) | |
490 | + self.load_config() | |
500 | 491 | |
501 | - # SIMULATOR MODE ONLY : flush previous commands to be sure to restart clean | |
502 | - if self.SIMULATOR_MODE: | |
503 | - self.print("flush previous commands to be sure to start in clean state") | |
504 | - Command.delete_pending_commands_for_agent(self.name) | |
505 | - | |
506 | - ''' | |
507 | - # SETUP | |
508 | - try: | |
509 | - self.config = get_object_or_404(Config, id=1) | |
510 | - # By default, set mode to SCHEDULER (False = REMOTE, which should never be the default) | |
511 | - self.config.global_mode = True | |
512 | - self.config.save() | |
513 | - # self.config = Config.objects.get(pk=1) | |
514 | - # self.config = Config.objects.get()[0] | |
515 | - except Exception as e: | |
516 | - # except Config.ObjectDoesNotExist: | |
517 | - self.printd("Config read (or write) exception", str(e)) | |
518 | - return -1 | |
519 | - ''' | |
492 | + if self.SIMULATOR_MODE: | |
493 | + self._log.print("[IN SIMULATOR MODE]") | |
494 | + else: | |
495 | + self._log.print("[IN NORMAL MODE]") | |
496 | + self.SIMULATOR_MAX_DURATION_SEC=None | |
497 | + self.start_time = time.time() | |
498 | + self.FOR_REAL = FOR_REAL | |
499 | + | |
500 | + self.init() | |
501 | + | |
502 | + # Avoid blocking on false "running" commands | |
503 | + # (old commands that stayed with "running" status when agent was killed) | |
504 | + Command.delete_commands_with_running_status_for_agent(self.name) | |
505 | + # SIMULATOR MODE ONLY : flush previous commands to be sure to restart clean | |
506 | + if self.SIMULATOR_MODE: | |
507 | + self.print("flush previous commands to be sure to start in clean state") | |
508 | + Command.delete_pending_commands_for_agent(self.name) | |
509 | + | |
510 | + ''' | |
511 | + # SETUP | |
512 | + try: | |
513 | + self.config = get_object_or_404(Config, id=1) | |
514 | + # By default, set mode to SCHEDULER (False = REMOTE, which should never be the default) | |
515 | + self.config.global_mode = True | |
516 | + self.config.save() | |
517 | + # self.config = Config.objects.get(pk=1) | |
518 | + # self.config = Config.objects.get()[0] | |
519 | + except Exception as e: | |
520 | + # except Config.ObjectDoesNotExist: | |
521 | + self.printd("Config read (or write) exception", str(e)) | |
522 | + return -1 | |
523 | + ''' | |
524 | + | |
525 | + self._iter_num = 1 | |
526 | + self.DO_MAIN_LOOP = True | |
527 | + # Main loop | |
528 | + while self.DO_MAIN_LOOP: | |
529 | + try: | |
530 | + self.main_loop(nb_iter,FOR_REAL) | |
531 | + if not self.DO_MAIN_LOOP: break | |
532 | + except KeyboardInterrupt: | |
533 | + # In case of CTRL-C, kill the current thread (process) before dying (in error) | |
534 | + self.print("CTRL-C Interrupted, I kill the current thread (process) before exiting") | |
535 | + self.kill_running_specific_cmd_if_exists() | |
536 | + exit(1) | |
537 | + #if self.DO_EXIT: exit(0) | |
538 | + | |
539 | + | |
540 | + | |
541 | + def main_loop(self, nb_iter:int=None, FOR_REAL:bool=True): | |
542 | + | |
543 | + # Bad number of iterations, so exit | |
544 | + if nb_iter is not None: | |
545 | + if nb_iter <= 0: | |
546 | + self.DO_MAIN_LOOP = False | |
547 | + return | |
548 | + # Number of iterations asked is reached, so exit | |
549 | + if self._iter_num > nb_iter: | |
550 | + print(f"Exit because number of iterations asked ({nb_iter}) has been reached") | |
551 | + self.DO_MAIN_LOOP = False | |
552 | + return | |
553 | + | |
554 | + self.print() | |
555 | + self.print() | |
556 | + #self.printd("-"*80) | |
557 | + self.print("-"*20, f"MAIN LOOP ITERATION {self._iter_num} (START)", "-"*20) | |
558 | + self.set_status(self.STATUS_MAIN_LOOP) | |
559 | + self.show_mode_and_status() | |
560 | + | |
561 | + # Wait a random number of sec before starting iteration | |
562 | + # (to let another agent having the chance to send a command before me) | |
563 | + random_waiting_sec = random.randint(0,5) | |
564 | + self.print(f"Waiting {random_waiting_sec} sec (random) before starting new iteration...") | |
565 | + time.sleep(random_waiting_sec) | |
566 | + | |
567 | + self.load_config() # only if changed | |
568 | + | |
569 | + # Log this agent status (update my current mode and status in DB) | |
570 | + self.log_agent_status() | |
571 | + | |
572 | + self.printd("------START COMMMAND PROCESSING------") | |
573 | + | |
574 | + # Purge commandes (every N iterations, delete old commands) | |
575 | + N=3 | |
576 | + if ((self._iter_num-1) % N) == 0: | |
577 | + self.print("Looking for old commands to purge...") | |
578 | + #Command.purge_old_commands_for_agent(self.name) | |
579 | + self.purge_old_commands_sent_to_me() | |
580 | + | |
581 | + # ROUTINE process | |
582 | + #if self.is_active(): | |
583 | + self.routine_process() | |
584 | + #self.printd("I am IDLE, so I bypass the routine_process (do not send any new command)") | |
585 | + | |
586 | + # Get next command to execute | |
587 | + cmd = self.get_next_valid_command() | |
588 | + #if cmd: cmd = self.general_process(cmd) | |
589 | + # Process this (next) command (if exists) | |
590 | + if cmd: cmd = self.command_process(cmd) | |
591 | + # if restart, exit this loop to restart from beginning | |
592 | + if self.DO_RESTART or self.DO_EXIT: | |
593 | + self.DO_MAIN_LOOP = False | |
594 | + return | |
520 | 595 | |
521 | - self._iter_num = 1 | |
522 | - # Main loop | |
523 | - while True: | |
596 | + self.printd("------END COMMMAND PROCESSING------") | |
524 | 597 | |
525 | - try: | |
598 | + #self.waitfor(self.mainloop_waittime) | |
526 | 599 | |
527 | - # Bad number of iterations, so exit | |
528 | - if nb_iter is not None: | |
529 | - if nb_iter <= 0: break | |
530 | - # Number of iterations asked is reached, so exit | |
531 | - if self._iter_num > nb_iter: | |
532 | - print(f"Exit because number of iterations asked ({nb_iter}) has been reached") | |
533 | - break | |
534 | - | |
535 | - self.print() | |
536 | - self.print() | |
537 | - #self.printd("-"*80) | |
538 | - self.print("-"*20, f"MAIN LOOP ITERATION {self._iter_num} (START)", "-"*20) | |
539 | - self.set_status(self.STATUS_MAIN_LOOP) | |
540 | - self.show_mode_and_status() | |
541 | - | |
542 | - # Wait a random number of sec before starting iteration | |
543 | - # (to let another agent having the chance to send a command before me) | |
544 | - random_waiting_sec = random.randint(0,5) | |
545 | - self.print(f"Waiting {random_waiting_sec} sec (random) before starting new iteration...") | |
546 | - time.sleep(random_waiting_sec) | |
547 | - | |
548 | - self.load_config() # only if changed | |
549 | - | |
550 | - # Log this agent status (update my current mode and status in DB) | |
551 | - self.log_agent_status() | |
552 | - | |
553 | - self.printd("------START COMMMAND PROCESSING------") | |
554 | - | |
555 | - # Purge commandes (every N iterations, delete old commands) | |
556 | - N=3 | |
557 | - if ((self._iter_num-1) % N) == 0: | |
558 | - self.print("Looking for old commands to purge...") | |
559 | - #Command.purge_old_commands_for_agent(self.name) | |
560 | - self.purge_old_commands_sent_to_me() | |
561 | - | |
562 | - # ROUTINE process | |
563 | - #if self.is_active(): | |
564 | - self.routine_process() | |
565 | - #self.printd("I am IDLE, so I bypass the routine_process (do not send any new command)") | |
566 | - | |
567 | - # Get next command to execute | |
568 | - cmd = self.get_next_valid_command() | |
569 | - #if cmd: cmd = self.general_process(cmd) | |
570 | - # Process this (next) command (if exists) | |
571 | - if cmd: cmd = self.command_process(cmd) | |
572 | - | |
573 | - self.printd("------END COMMMAND PROCESSING------") | |
574 | - | |
575 | - #self.waitfor(self.mainloop_waittime) | |
576 | - | |
577 | - self.print("-"*20, "MAIN LOOP ITERATION (END)", "-"*20) | |
578 | - #self.do_log(LOG_DEBUG, "Ending main loop iteration") | |
579 | - | |
580 | - # (simulator only) Exit if max duration is reached | |
581 | - if self.SIMULATOR_MAX_DURATION_SEC and (time.time()-start_time > self.SIMULATOR_MAX_DURATION_SEC): | |
582 | - self.print("Exit because of max duration set to ", self.SIMULATOR_MAX_DURATION_SEC, "s") | |
583 | - self.kill_running_specific_cmd_if_exists() | |
584 | - if self.SIMULATOR_MODE and self.SIMULATOR_WITH_TEST: self.simulator_test_results() | |
585 | - break | |
600 | + self.print("-"*20, "MAIN LOOP ITERATION (END)", "-"*20) | |
601 | + #self.do_log(LOG_DEBUG, "Ending main loop iteration") | |
586 | 602 | |
587 | - self._iter_num += 1 | |
603 | + # (simulator only) Exit if max duration is reached | |
604 | + if self.SIMULATOR_MAX_DURATION_SEC and (time.time()-self.start_time > self.SIMULATOR_MAX_DURATION_SEC): | |
605 | + self.print("Exit because of max duration set to ", self.SIMULATOR_MAX_DURATION_SEC, "s") | |
606 | + self.kill_running_specific_cmd_if_exists() | |
607 | + if self.SIMULATOR_MODE and self.SIMULATOR_WITH_TEST: self.simulator_test_results() | |
608 | + self.DO_MAIN_LOOP = False | |
609 | + return | |
588 | 610 | |
589 | - except KeyboardInterrupt: | |
590 | - # In case of CTRL-C, kill the current thread (process) before dying (in error) | |
591 | - self.print("CTRL-C Interrupted, I kill the current thread (process) before exiting") | |
592 | - self.kill_running_specific_cmd_if_exists() | |
593 | - exit(1) | |
611 | + self._iter_num += 1 | |
594 | 612 | |
595 | 613 | |
596 | 614 | |
... | ... | @@ -932,7 +950,8 @@ class Agent: |
932 | 950 | Command.show_commands(commands) |
933 | 951 | #if self.SIMULATOR_MODE and self.SIMULATOR_WITH_TEST and self.SIMULATOR_COMMANDS_DEST == "myself": self.simulator_test_results() |
934 | 952 | if self.SIMULATOR_MODE and self.SIMULATOR_WITH_TEST: self.simulator_test_results() |
935 | - exit(0) | |
953 | + #self.DO_EXIT=True | |
954 | + #exit(0) | |
936 | 955 | # Command is executed, so return None |
937 | 956 | return None |
938 | 957 | |
... | ... | @@ -957,23 +976,27 @@ class Agent: |
957 | 976 | cmd.set_as_running() |
958 | 977 | |
959 | 978 | # Executing command |
960 | - if cmd.name == "go_active": | |
979 | + if cmd.name == "go_active": | |
961 | 980 | self.set_active() |
962 | 981 | cmd.set_result("I am now active") |
963 | 982 | time.sleep(1) |
964 | - elif cmd.name == "go_idle": | |
983 | + elif cmd.name == "go_idle": | |
965 | 984 | self.set_idle() |
966 | 985 | cmd.set_result("I am now idle") |
967 | 986 | time.sleep(1) |
968 | 987 | elif cmd.name in ("flush_commands"): |
969 | 988 | self.print("flush_commands received: Delete all pending commands") |
970 | 989 | Command.delete_pending_commands_for_agent(self.name) |
971 | - # If cmd is "abort" or "exit", kill any currently running thread | |
972 | - elif cmd.name in ("abort", "exit"): | |
990 | + elif cmd.name in ("abort", "exit", "restart_init"): | |
973 | 991 | #self.printd("Current pending commands are:") |
974 | 992 | #Command.show_commands(self._pending_commands) |
975 | 993 | self.print("Aborting current executing command if exists:") |
976 | 994 | self.kill_running_specific_cmd_if_exists() |
995 | + if cmd.name == "restart_init": | |
996 | + self.print("restart_init received: Restarting from init()") | |
997 | + self.DO_RESTART=True | |
998 | + elif cmd.name == "exit": | |
999 | + self.DO_EXIT=True | |
977 | 1000 | else: |
978 | 1001 | name = cmd.name |
979 | 1002 | args = None | ... | ... |
src/common/models.py
... | ... | @@ -348,7 +348,11 @@ class Command(models.Model): |
348 | 348 | "CMD_KILLED", # cde ignorée (je suis idle… et j’ai ignoré cette commande, et je passe à la cde suivante) |
349 | 349 | "CMD_OUTOFDATE" # cde périmée |
350 | 350 | ) |
351 | - GENERIC_COMMANDS = ["eval", "go_idle", "go_active", "flush_commands", "abort", "exit", "restart_init"] | |
351 | + GENERIC_COMMANDS = [ | |
352 | + "eval", "go_idle", "go_active", | |
353 | + # Commands executed in priority (even if other pending commands exist) | |
354 | + "flush_commands", "abort", "exit", "restart_init" | |
355 | + ] | |
352 | 356 | #COMMANDS_PEREMPTION_HOURS = 48 |
353 | 357 | COMMANDS_PEREMPTION_HOURS = 60/60 |
354 | 358 | COMMANDS_VALIDITY_DURATION_SEC_DEFAULT = 30 | ... | ... |