From 97777484a98e7b81bdf29033c26aae3de5ed2fa0 Mon Sep 17 00:00:00 2001 From: Jeremy Stanley Date: Mon, 26 Apr 2021 01:21:45 +0000 Subject: [PATCH] Be more robust with elapsed time counter Stress testing identified a rare startup race if a user connected before the elapsed time counter was initialized. The odds of encountering this in the wild are close to nonexistent, but it was introducing occasional test failures. Solve the race by reordering the actions taken on each pulse, so that the counter is initialized before the listening socket is created. Also force all access to the counter through setter/getter methods and wrap in try/except to always return a value and properly create the counter and containing element if it doesn't yet exist. --- mudpy/misc.py | 54 +++++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/mudpy/misc.py b/mudpy/misc.py index 6d61085..5270acd 100644 --- a/mudpy/misc.py +++ b/mudpy/misc.py @@ -475,7 +475,19 @@ class Universe: def get_time(self): """Convenience method to get the elapsed time counter.""" - return self.groups["internal"]["counters"].get("elapsed") + try: + return self.groups["internal"]["counters"].get("elapsed", 0) + except KeyError: + return 0 + + def set_time(self, elapsed): + """Convenience method to set the elapsed time counter.""" + try: + self.groups["internal"]["counters"].set("elapsed", elapsed) + except KeyError: + # add an element for counters if it doesn't exist + Element("internal.counters", universe) + self.groups["internal"]["counters"].set("elapsed", elapsed) def add_group(self, group, fallback=None): """Set up group tracking/metadata.""" @@ -693,7 +705,7 @@ class User: if "$_(time)" in prompt: prompt = prompt.replace( "$_(time)", - str(universe.groups["internal"]["counters"].get("elapsed"))) + str(universe.get_time())) # Append a single space for clear separation from user input if prompt[-1] != " ": @@ -1407,22 +1419,8 @@ def first_word(text, separator=" "): def on_pulse(): """The things which should happen on each pulse, aside from reloads.""" - # open the listening socket if it hasn't been already - if not hasattr(universe, "listening_socket"): - universe.initialize_server_socket() - - # assign a user if a new connection is waiting - user = check_for_connection(universe.listening_socket) - if user: - universe.userlist.append(user) - - # iterate over the connected users - for user in universe.userlist: - user.pulse() - - # add an element for counters if it doesn't exist - if "counters" not in universe.groups.get("internal", {}): - Element("internal.counters", universe) + # increase the elapsed increment counter + universe.set_time(universe.get_time() + 1) # update the log every now and then if not universe.groups["internal"]["counters"].get("mark"): @@ -1450,16 +1448,22 @@ def on_pulse(): ) - 1 ) + # open the listening socket if it hasn't been already + if not hasattr(universe, "listening_socket"): + universe.initialize_server_socket() + + # assign a user if a new connection is waiting + user = check_for_connection(universe.listening_socket) + if user: + universe.userlist.append(user) + + # iterate over the connected users + for user in universe.userlist: + user.pulse() + # pause for a configurable amount of time (decimal seconds) time.sleep(universe.contents["mudpy.timing"].get("increment")) - # increase the elapsed increment counter - universe.groups["internal"]["counters"].set( - "elapsed", universe.groups["internal"]["counters"].get( - "elapsed", 0 - ) + 1 - ) - def reload_data(): """Reload all relevant objects.""" -- 2.11.0