Commit 3381a718aa9e021a4a7c8d84155f4c82615f2159

Authored by Etienne Pallier
1 parent 30b22ee6
Exists in dev

Agent : command purge_commands() implemented

Showing 3 changed files with 70 additions and 30 deletions   Show diff stats
README.md
... ... @@ -67,14 +67,14 @@ This software has been tested and validated with the following configurations :
67 67 --------------------------------------------------------------------------------------------
68 68 ## LAST VERSION
69 69  
70   -Date: 05/03/2019
  70 +Date: 06/03/2019
71 71  
72 72 Author: E. Pallier
73 73  
74   -VERSION: 0.20.6
  74 +VERSION: 0.20.7
75 75  
76 76 Comment:
77   - Agent : agentX working with a command simulator
  77 + Agent : command purge_commands() implemented
78 78  
79 79  
80 80 --------------------------------------------------------------------------------------------
... ...
src/agent/Agent.py
... ... @@ -10,7 +10,7 @@ VERSION = "0.4"
10 10 #from __future__ import absolute_import
11 11  
12 12 import time
13   -import datetime
  13 +from datetime import datetime, timedelta
14 14 import os
15 15  
16 16  
... ... @@ -90,15 +90,12 @@ class Agent:
90 90 SIMULATOR_MODE = True
91 91 SIMULATOR_COMMANDS = iter([
92 92 "go_active",
93   - "go_idle",
94 93  
95   - "go_active",
96 94 "go_idle",
  95 + "specific_not_executed_because_idle",
97 96  
98 97 "go_active",
99   -
100   - "specific_1",
101   - "specific_2",
  98 + "specific_executed_because_not_idle",
102 99  
103 100 "stop"
104 101 ])
... ... @@ -106,10 +103,12 @@ class Agent:
106 103 #_current_test_cmd = None
107 104 #_nb_test_cmds = 0
108 105  
109   -
110 106 # Run for real, otherwise just print messages without really doing anything
111 107 FOR_REAL = True
112 108  
  109 + #COMMANDS_PEREMPTION_HOURS = 48
  110 + COMMANDS_PEREMPTION_HOURS = 60/60
  111 +
113 112 name = "Generic Agent"
114 113 mainloop_waittime = 3
115 114 subloop_waittime = 2
... ... @@ -133,6 +132,7 @@ class Agent:
133 132  
134 133 _agent_survey = None
135 134  
  135 + _iter_num = 0
136 136  
137 137 def __init__(self, name:str=None, config_filename:str=None):
138 138 self.set_mode(self.MODE_IDLE)
... ... @@ -202,16 +202,13 @@ class Agent:
202 202  
203 203 # Main loop
204 204 while True:
205   - self.set_status(self.STATUS_MAIN_LOOP)
206   -
207   - """
208   - A chaque tour de boucle, remplir champ "iamalive" avec timestamp + durée validité (> temps iteration, n minutes par défaut)
209   - + nom agent dans table agents_survey (nom agent + mode + status + updated timestamp)
210   - """
211 205  
212 206 print()
213 207 print()
214   - print("Starting main loop iteration...")
  208 + #print("-"*80)
  209 +
  210 + print("-"*20, f"MAIN LOOP ITERATION {self._iter_num} (START)", "-"*20)
  211 + self.set_status(self.STATUS_MAIN_LOOP)
215 212 self.show_mode_and_status()
216 213  
217 214 self.load_config()
... ... @@ -241,14 +238,40 @@ class Agent:
241 238 if cmd: self.specific_process(cmd)
242 239 print("---")
243 240  
  241 + # Every N iterations, delete old commands
  242 + N=3
  243 + if (self._iter_num % N) == 0: self.purge_commands()
  244 +
244 245 self.waitfor(self.mainloop_waittime)
245 246  
246   - print("Ending main loop iteration...")
  247 + print("-"*20, "MAIN LOOP ITERATION (END)", "-"*20)
  248 + #print("-"*80)
247 249  
248 250 #self.do_log(LOG_DEBUG, "Ending main loop iteration")
249 251  
  252 + self._iter_num += 1
250 253  
251 254  
  255 + def purge_commands(self):
  256 + """
  257 + Delete commands (which I am recipient of) older than COMMANDS_PEREMPTION_HOURS (like 48h)
  258 +
  259 + NB: datetime.utcnow() is equivalent to datetime.now(timezone.utc)
  260 + """
  261 +
  262 + COMMAND_PEREMPTION_DATE_FROM_NOW = datetime.utcnow() - timedelta(hours = self.COMMANDS_PEREMPTION_HOURS)
  263 + print("peremption date", COMMAND_PEREMPTION_DATE_FROM_NOW)
  264 + old_commands = Command.objects.filter(
  265 + # only commands for me
  266 + receiver = self.name,
  267 + # only pending commands
  268 + sender_deposit_time__lt = COMMAND_PEREMPTION_DATE_FROM_NOW,
  269 + )
  270 + if old_commands.exists():
  271 + print("Found old commands to delete:")
  272 + for cmd in old_commands: print(cmd)
  273 + old_commands.delete()
  274 +
252 275 def waitfor(self, nbsec):
253 276 print(f"Now, waiting for {nbsec} seconds...")
254 277 time.sleep(nbsec)
... ... @@ -423,9 +446,8 @@ class Agent:
423 446 print(cmd)
424 447  
425 448 # 3) Update read time to say that the command has been READ
426   - assert cmd.receiver_read_time is None # f"Command {cmd} should not have been already read !!"
427   - cmd.receiver_read_time = datetime.datetime.now()
428   - cmd.save()
  449 + ##assert cmd.receiver_read_time is None # f"Command {cmd} should not have been already read !!"
  450 + cmd.set_as_read()
429 451 return cmd
430 452  
431 453  
... ... @@ -439,22 +461,18 @@ class Agent:
439 461  
440 462 # If expired command, change its status to expired and return
441 463 elapsed_time = cmd.receiver_read_time - cmd.sender_deposit_time
442   - max_time = datetime.timedelta(seconds = cmd.validity_duration_sec)
  464 + max_time = timedelta(seconds = cmd.validity_duration_sec)
443 465 print(f"Elapsed time is {elapsed_time}, (max is {max_time})")
444 466 if elapsed_time > max_time:
445 467 print("This command is expired, so mark it as expired, and ignore it")
446 468 #cmd.delete()
447   - cmd.receiver_status_code = Command.CMD_STATUS_CODES.CMD_OUTOFDATE
448   - cmd.save()
  469 + cmd.set_as_outofdate()
449 470 return None
450 471  
451 472 # If cmd is generic, execute it, change its status to executed, and return
452 473 if cmd.is_generic():
453 474 print("This command is generic, execute it...")
454 475 self.exec_generic_cmd(cmd)
455   - print("...Generic cmd has been executed")
456   - cmd.receiver_status_code = Command.CMD_STATUS_CODES.CMD_EXECUTED
457   - cmd.save()
458 476 if cmd.command == "stop": exit(0)
459 477 return None
460 478  
... ... @@ -463,8 +481,7 @@ class Agent:
463 481 # cmd is not generic but, as I am idle, change its status to SKIPPED, ignore it, and return
464 482 if self.mode == self.MODE_IDLE:
465 483 print("This command is not generic but, as I am IDLE, I mark it SKIPPED and ignore it")
466   - cmd.receiver_status_code = Command.CMD_STATUS_CODES.CMD_SKIPPED
467   - cmd.save()
  484 + cmd.set_as_skipped()
468 485 return None
469 486  
470 487 # Je suis pas idle et cde pas générique: je la traite pas, elle sera traitée par core_process :
... ... @@ -475,10 +492,15 @@ class Agent:
475 492  
476 493  
477 494 def exec_generic_cmd(self, cmd:Command):
478   - time.sleep(1)
  495 + cmd.set_as_running()
  496 + # Executing command
479 497 if cmd.command == "go_active": self.set_active()
480 498 elif cmd.command == "go_idle": self.set_idle()
481 499 elif cmd.command == "stop": pass
  500 + time.sleep(1)
  501 + cmd.set_as_executed()
  502 + print("...Generic cmd has been executed")
  503 +
482 504  
483 505  
484 506 def do_log(self):
... ...
src/common/models.py
1 1 ##from __future__ import unicode_literals
2 2  
3 3 from enum import Enum
  4 +from datetime import datetime
4 5  
5 6 from django.contrib.auth.models import AbstractUser
6 7 from django.db import models
... ... @@ -276,6 +277,23 @@ class Command(models.Model):
276 277 """
277 278 return self.command in self.GENERIC_COMMANDS
278 279  
  280 + def set_as_read(self):
  281 + self.receiver_read_time = datetime.utcnow()
  282 + self.save()
  283 +
  284 + def set_as_outofdate(self):
  285 + self.set_status_to(self.CMD_STATUS_CODES.CMD_OUTOFDATE)
  286 + def set_as_skipped(self):
  287 + self.set_status_to(self.CMD_STATUS_CODES.CMD_SKIPPED)
  288 + def set_as_running(self):
  289 + self.set_status_to(self.CMD_STATUS_CODES.CMD_RUNNING)
  290 + def set_as_executed(self):
  291 + self.set_status_to(self.CMD_STATUS_CODES.CMD_EXECUTED)
  292 +
  293 + def set_status_to(self, status:str):
  294 + self.receiver_status_code = status
  295 + self.save()
  296 +
279 297  
280 298 class AgentSurvey(models.Model):
281 299 """
... ...