Repository: RocketMap/RocketMap

Issue:
Gym info being requested multiple times.
This was always the case but hidden under a distinct in Gym.get_gyms() but also due to the new 1Km range we did in raids PR this will happen more usually as there is no control that avoids scanning the same gym twice, I did monitor and I constantly have 4-5 gyms in that situation and that's even discounting the gyms that where requested twice but cleared in between.

We should add some kind of shared control to avoid this situation.


Discussion:

Resolving patch:
diff --git a/pogom/search.py b/pogom/search.py
--- a/pogom/search.py
+++ b/pogom/search.py
@@ -28,6 +28,7 @@
 import schedulers
 import terminalsize
 import timeit
+import threading
 
 from datetime import datetime
 from threading import Thread, Lock
@@ -37,6 +38,7 @@
 from requests.adapters import HTTPAdapter
 from requests.packages.urllib3.util.retry import Retry
 from distutils.version import StrictVersion
+from cachetools import TTLCache
 
 from pgoapi.utilities import f2i
 from pgoapi import utilities as util
@@ -54,6 +56,7 @@
 log = logging.getLogger(__name__)
 
 loginDelayLock = Lock()
+gym_cache_lock = threading.Lock()
 
 
 # Thread to handle user input.
@@ -338,6 +341,10 @@ def search_overseer_thread(args, new_location_queue, control_flags, heartb,
     api_check_time = 0
     hashkeys_last_upsert = timeit.default_timer()
     hashkeys_upsert_min_delay = 5.0
+    gym_cache = None
+
+    if args.gym_info:
+        gym_cache = TTLCache(maxsize=10000, ttl=60)
 
     '''
     Create a queue of accounts for workers to pull from. When a worker has
@@ -452,14 +459,14 @@ def search_overseer_thread(args, new_location_queue, control_flags, heartb,
             'proxy_display': proxy_display,
             'proxy_url': proxy_url,
         }
+        argset = (
+            args, account_queue, account_sets, account_failures,
+            account_captchas, control_flags, threadStatus[workerId],
+            db_updates_queue, wh_queue, scheduler, key_scheduler, gym_cache)
 
         t = Thread(target=search_worker_thread,
                    name='search-worker-{}'.format(i),
-                   args=(args, account_queue, account_sets,
-                         account_failures, account_captchas,
-                         control_flags, threadStatus[workerId],
-                         db_updates_queue, wh_queue,
-                         scheduler, key_scheduler))
+                   args=argset)
         t.daemon = True
         t.start()
 
@@ -752,10 +759,9 @@ def generate_hive_locations(current_location, step_distance,
     return results
 
 
-def search_worker_thread(args, account_queue, account_sets,
-                         account_failures, account_captchas,
-                         control_flags, status, dbq, whq,
-                         scheduler, key_scheduler):
+def search_worker_thread(args, account_queue, account_sets, account_failures,
+                         account_captchas, control_flags, status, dbq, whq,
+                         scheduler, key_scheduler, gym_cache):
 
     log.debug('Search worker thread starting...')
 
@@ -1025,6 +1031,18 @@ def search_worker_thread(args, account_queue, account_sets,
                     # Build a list of gyms to update.
                     gyms_to_update = {}
                     for gym in parsed['gyms'].values():
+                        with gym_cache_lock:
+                            if gym['gym_id'] in gym_cache:
+                                log.debug(
+                                    ('Skipping update of gym @ %f/%f, ' +
+                                     'already in progress.'),
+                                    gym['latitude'], gym['longitude'])
+                                continue
+                            else:
+                                # Set the gym as in progress it will just be
+                                # locked for 60 seconds due to TTL eviction.
+                                gym_cache[gym['gym_id']] = True
+
                         # Can only get gym details within 1km of our position.
                         distance = calc_distance(
                             step_location, [gym['latitude'], gym['longitude']])


Test patch: