Commit cf8b102563c3679ade40291a28e5a0c40864c01a

Authored by Etienne Pallier
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
... ...