class Service: # pylint: disable=R0902 """Core service worker object.""" empty = False stopped = False next_page = 1 def __init__(self): """Initiate sync elements on creation.""" self.logging = logging.getLogger("LeagueRankings") self.logging.setLevel(logging.INFO) handler = logging.StreamHandler() handler.setLevel(logging.INFO) handler.setFormatter( logging.Formatter("%(asctime)s [Subscriber] %(message)s")) self.logging.addHandler(handler) self.proxy = os.environ["PROXY_URL"] self.server = os.environ["SERVER"] self.db = PostgresConnector(user=self.server.lower()) self.url = (f"http://{self.server.lower()}.api.riotgames.com/lol/" + "league-exp/v4/entries/RANKED_SOLO_5x5/%s/%s?page=%s") self.rankmanager = RankManager() self.retry_after = datetime.now() def shutdown(self): """Called on shutdown init.""" self.stopped = True async def init(self): """Override of the default init function. Initiate the Rankmanager object. """ await self.rankmanager.init() async def process_rank(self, tier, division, worker=5): task_sets = await asyncio.gather(*[ asyncio.create_task( self.async_worker(tier, division, offset=i, worker=worker)) for i in range(worker) ]) tasks = {} for entry in task_sets: tasks = {**tasks, **entry} min_rank = tiers[tier] * 400 + rank[division] * 100 self.logging.info("Found %s unique user.", len(tasks)) async with self.db.get_connection() as db: latest = await db.fetch( """ SELECT summoner_id, rank, wins, losses FROM %s.summoner WHERE rank >= $1 AND rank <= $2 """ % self.server.lower(), min_rank, min_rank + 100, ) for line in latest: if line["summoner_id"] in tasks: task = tasks[line["summoner_id"]] if task == ( line["summoner_id"], int(line["rank"]), int(line["wins"]), int(line["losses"]), ): del tasks[line["summoner_id"]] self.logging.info("Upserting %s changed user.", len(tasks)) if tasks: prepared = await db.prepare( """ INSERT INTO %s.summoner (summoner_id, rank, wins, losses) VALUES ($1, $2, $3, $4) ON CONFLICT (summoner_id) DO UPDATE SET rank = EXCLUDED.rank, wins = EXCLUDED.wins, losses = EXCLUDED.losses """ % self.server.lower()) await prepared.executemany(tasks.values()) async def async_worker(self, tier, division, offset, worker): failed = False empty = False page = offset + 1 tasks = [] while (not empty or failed) and not self.stopped: if (delay := (self.retry_after - datetime.now()).total_seconds()) > 0: await asyncio.sleep(delay) async with aiohttp.ClientSession() as session: try: content = await self.fetch(session, url=self.url % (tier, division, page)) if len(content) == 0: self.logging.info("Page %s is empty.", page) empty = True continue tasks += content except (RatelimitException, Non200Exception): failed = True except NotFoundException: empty = True if not failed: page += worker failed = False unique_tasks = {} for task in tasks: unique_tasks[task["summonerId"]] = ( task["summonerId"], int(tiers[task["tier"]] * 400 + rank[task["rank"]] * 100 + task["leaguePoints"]), int(task["wins"]), int(task["losses"]), ) return unique_tasks
class Service: """Core service worker object.""" queues = None def __init__(self): """Initiate sync elements on creation.""" self.logging = logging.getLogger("MatchTimeline") level = logging.INFO self.logging.setLevel(level) handler = logging.StreamHandler() handler.setLevel(level) handler.setFormatter( logging.Formatter("%(asctime)s [MatchTimeline] %(message)s")) self.logging.addHandler(handler) self.proxy = os.environ["PROXY_URL"] self.server = os.environ["SERVER"] self.batch_size = int(os.environ["BATCH_SIZE"]) self.redis = RedisConnector() self.db = PostgresConnector(user=self.server.lower()) self.db.set_prepare(self.prepare) self.stopped = False self.retry_after = datetime.now() self.url = (f"http://{self.server.lower()}.api.riotgames.com/lol/" + "match/v4/timelines/by-match/%s") self.buffered_elements = ( {} ) # Short term buffer to keep track of currently ongoing requests self.active_tasks = [] def shutdown(self): """Called on shutdown init.""" self.stopped = True async def prepare(self, conn): self.match_update = await conn.prepare(""" UPDATE %s.match SET timeline_pulled = TRUE WHERE match_id = $1 """ % self.server.lower()) self.match_data_update = await conn.prepare(""" UPDATE %s.match_data SET timeline = $1 WHERE match_id = $2 """ % self.server.lower()) async def flush_manager(self, match_timelines): """Update entries in postgres once enough tasks are done.""" try: update_match_sets = [] update_match_data_sets = [] for match in match_timelines: if not match[1]: continue timeline = match[1] # Team Details update_match_sets.append((int(match[0]), )) update_match_data_sets.append(( json.dumps(timeline), int(match[0]), )) if update_match_sets: async with self.db.get_connection() as db: async with db.transaction(): await self.match_data_update.executemany( update_match_data_sets) await self.match_update.executemany(update_match_sets) self.logging.info("Inserted %s match_timelines.", len(update_match_sets)) except Exception as err: traceback.print_tb(err.__traceback__) self.logging.info(err) async def get_task(self): """Return tasks to the async worker.""" async with self.redis.get_connection() as buffer: if not (tasks := await buffer.spop( "%s_match_timeline_tasks" % self.server, self.batch_size)): return tasks if self.stopped: return start = int(datetime.utcnow().timestamp()) for entry in tasks: await buffer.zadd( "%s_match_timeline_in_progress" % self.server, start, entry) return tasks
class Manager: stopped = False def __init__(self): self.logging = logging.getLogger("Main") level = logging.INFO self.logging.setLevel(level) handler = logging.StreamHandler() handler.setLevel(level) handler.setFormatter(logging.Formatter("%(asctime)s %(message)s")) self.logging.addHandler(handler) self.limit = int(os.environ["LIMIT"]) self.server = os.environ["SERVER"] self.block_limit = int(os.environ["TASK_BLOCKING"]) self.details_cutoff = os.environ["DETAILS_CUTOFF"] self.redis = RedisConnector() self.db = PostgresConnector(user=self.server.lower()) self.db.set_prepare(self.prepare) async def init(self): async with self.redis.get_connection() as buffer: await buffer.delete("%s_match_details_in_progress" % self.server) await buffer.delete("%s_match_details_tasks" % self.server) def shutdown(self): self.stopped = True async def prepare(self, conn): self.insert_data_entry = await conn.prepare(""" INSERT INTO %s.match_data (match_id, queue, timestamp) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING; """ % self.server.lower()) async def get_tasks(self): """Return tasks and full_refresh flag. If there are non-initialized user found only those will be selected. If none are found a list of the user with the most new games are returned. """ async with self.db.get_connection() as db: tasks = await db.fetch( """ SELECT match_id, queue, timestamp FROM %s.match WHERE details_pulled IS NULL AND timestamp::date >= %s LIMIT $1; """ % (self.server.lower(), self.details_cutoff), self.limit * 2, ) tasks_formatted = [[ int(task["match_id"]), int(task["queue"]), task["timestamp"] ] for task in tasks] await self.insert_data_entry.executemany(tasks_formatted) return tasks async def run(self): await self.init() min_count = 100 blocked = False try: while not self.stopped: # Drop timed out tasks limit = int((datetime.utcnow() - timedelta(minutes=self.block_limit)).timestamp()) async with self.redis.get_connection() as buffer: await buffer.zremrangebyscore( "%s_match_details_in_progress" % self.server, max=limit) # Check remaining buffer size if (size := await buffer.scard("%s_match_details_tasks" % self.server)) >= self.limit: await asyncio.sleep(10) continue # Pull new tasks result = await self.get_tasks() if len(result) - size < min_count: if not blocked: self.logging.info("%s tasks remaining.", size) self.logging.info("No tasks found.") blocked = True min_count -= 1 await asyncio.sleep(30) continue min_count = 100 self.logging.info("%s tasks remaining.", size) self.logging.info("Found %s tasks.", len(result)) # Add new tasks for entry in result: # Each entry will always be refered to by account_id if await buffer.zscore( "%s_match_details_in_progress" % self.server, entry["match_id"], ): continue # Insert task hook await buffer.sadd( "%s_match_details_tasks" % self.server, entry["match_id"]) self.logging.info( "Filled tasks to %s.", await buffer.scard("%s_match_details_tasks" % self.server), ) await asyncio.sleep(1) await asyncio.sleep(5) except Exception as err: traceback.print_tb(err.__traceback__) self.logging.info(err)
class Service: """Core service worker object.""" queues = None def __init__(self): """Initiate sync elements on creation.""" self.logging = logging.getLogger("MatchHistory") level = logging.INFO self.logging.setLevel(level) handler = logging.StreamHandler() handler.setLevel(level) handler.setFormatter( logging.Formatter("%(asctime)s [MatchHistory] %(message)s")) self.logging.addHandler(handler) self.server = os.environ["SERVER"] self.redis = RedisConnector() self.db = PostgresConnector(user=self.server.lower()) self.db.set_prepare(self.prepare) self.stopped = False self.retry_after = datetime.now() self.url = ( f"http://{self.server.lower()}.api.riotgames.com/lol/" + "match/v4/matchlists/by-account/%s?beginIndex=%s&endIndex=%s") if "QUEUES" in os.environ: self.queues = [ int(queue) for queue in os.environ["QUEUES"].split(",") ] self.url = self.url + "&queue=" + os.environ["QUEUES"] self.buffered_elements = ( {} ) # Short term buffer to keep track of currently ongoing requests self.active_tasks = [] self.insert_query = None def shutdown(self): """Called on shutdown init.""" self.stopped = True async def flush_manager(self, matches, account_id, keys): """Update entries in postgres once enough tasks are done.""" try: sets = [] for entry in matches: if self.queues and int(entry["queue"]) not in self.queues: continue sets.append(( entry["gameId"], entry["queue"], datetime.fromtimestamp(entry["timestamp"] // 1000), )) async with self.db.get_connection() as db: if sets: await self.insert_query.executemany(sets) self.logging.info("Inserted %s sets for %s.", len(sets), account_id) await db.execute( """ UPDATE %s.summoner SET wins_last_updated = $1, losses_last_updated = $2 WHERE account_id = $3 """ % self.server.lower(), int(keys["wins"]), int(keys["losses"]), account_id, ) except Exception as err: traceback.print_tb(err.__traceback__) self.logging.info(err) async def prepare(self, connection): self.insert_query = await connection.prepare(""" INSERT INTO %s.match (match_id, queue, timestamp) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING; """ % self.server.lower()) async def get_task(self): """Return tasks to the async worker.""" async with self.redis.get_connection() as buffer: while (not (task := await buffer.zpopmax( "%s_match_history_tasks" % self.server, 1)) and not self.stopped): await asyncio.sleep(5) if self.stopped: return keys = await buffer.hgetall("%s:%s:%s" % (self.server, task[0], task[1])) await buffer.delete("%s:%s:%s" % (self.server, task[0], task[1])) start = int(datetime.utcnow().timestamp()) await buffer.zadd("match_history_in_progress", start, task[0]) return [task[0], int(task[1])], keys
class Manager: stopped = False def __init__(self, queues): self.logging = logging.getLogger("Main") level = logging.INFO self.logging.setLevel(level) handler = logging.StreamHandler() handler.setLevel(level) handler.setFormatter(logging.Formatter("%(asctime)s %(message)s")) self.logging.addHandler(handler) self.server = os.environ["SERVER"] self.batchsize = int(os.environ["BATCH_SIZE"]) self.db = PostgresConnector(user=self.server.lower()) self.allowed_queues = queues def shutdown(self): self.stopped = True async def get_tasks(self): """Return tasks and full_refresh flag. If there are non-initialized user found only those will be selected. If none are found a list of the user with the most new games are returned. """ async with self.db.get_connection() as db: tasks = await db.fetch( """ SELECT match_id, details, timeline FROM %s.match_data WHERE details IS NOT NULL AND timeline IS NOT NULL AND roleml IS NULL AND queue IN (%s) AND duration >= 60 * 12 LIMIT $1; """ % (self.server.lower(), ",".join(self.allowed_queues)), self.batchsize, ) return tasks async def update_db(self, results): """Update matches in the db.""" async with self.db.get_connection() as db: await db.executemany( """ UPDATE %s.match_data SET roleml = $1 WHERE match_id = $2 """ % self.server.lower(), results, ) async def run(self): empty = False try: while not self.stopped: tasks = await self.get_tasks() if len(tasks) == 0: if not empty: self.logging.info("Found no tasks, Sleeping") empty = True await asyncio.sleep(15) continue empty = False results = [] for task in tasks: try: results.append([ json.dumps( roleml.predict( json.loads(task["details"]), json.loads(task["timeline"]), )), task["match_id"], ]) except (IncorrectMap, MatchTooShort): results.append(["{}", task["match_id"]]) await self.update_db(results) self.logging.info("Predicted %s matches.", len(results)) await asyncio.sleep(5) except Exception as err: traceback.print_tb(err.__traceback__) self.logging.info(err)
class Manager: stopped = False def __init__(self): self.logging = logging.getLogger("Main") level = logging.INFO self.logging.setLevel(level) handler = logging.StreamHandler() handler.setLevel(level) handler.setFormatter(logging.Formatter("%(asctime)s %(message)s")) self.logging.addHandler(handler) self.server = os.environ["SERVER"].lower() self.block_limit = int(os.environ["TASK_BLOCKING"]) self.redis = RedisConnector() self.db = PostgresConnector(user=self.server.lower()) async def init(self): async with self.redis.get_connection() as connection: await connection.delete("%s_summoner_id_in_progress" % self.server) await connection.delete("%s_summoner_id_tasks" % self.server) def shutdown(self): self.stopped = True async def run(self): await self.init() minimum = 100 # Local minimum that gets reset every time tasks are inserted blocked = False while not self.stopped: # Drop timed out tasks limit = int( (datetime.utcnow() - timedelta(minutes=self.block_limit)).timestamp() ) async with self.redis.get_connection() as buffer: await buffer.zremrangebyscore( "%s_summoner_id_in_progress" % self.server, max=limit ) # Check remaining buffer size if ( size := await buffer.scard("%s_summoner_id_tasks" % self.server) ) >= 1000: await asyncio.sleep(10) continue async with self.db.get_connection() as db: result = await db.fetch( """ SELECT summoner_id FROM %s.summoner WHERE account_id IS NULL LIMIT 2000; """ % self.server.lower() ) if len(result) - size < minimum: if not blocked: self.logging.info("No tasks found.") blocked = True minimum -= 1 await asyncio.sleep(30) continue minimum = 100 self.logging.info("%s tasks remaining.", size) async with self.redis.get_connection() as buffer: for entry in result: if await buffer.sismember( "%s_summoner_id_tasks" % self.server, entry["summoner_id"] ): continue await buffer.sadd( "%s_summoner_id_tasks" % self.server, entry["summoner_id"] ) if await buffer.scard("%s_summoner_id_tasks" % self.server) >= 2000: break self.logging.info( "Filled tasks to %s.", await buffer.scard("%s_summoner_id_tasks" % self.server), ) await asyncio.sleep(5) await self.redis.close() await self.db.close()
class Manager: stopped = False def __init__(self): self.logging = logging.getLogger("Main") level = logging.INFO self.logging.setLevel(level) handler = logging.StreamHandler() handler.setLevel(level) handler.setFormatter(logging.Formatter("%(asctime)s %(message)s")) self.min_matches = int(os.environ["MIN_MATCHES"]) self.server = os.environ["SERVER"] self.logging.addHandler(handler) self.redis = RedisConnector() self.db = PostgresConnector(user=self.server.lower()) async def init(self): async with self.redis.get_connection() as buffer: await buffer.delete("%s_match_history_in_progress" % self.server) await buffer.delete("%s_match_history_tasks" % self.server) def shutdown(self): self.stopped = True async def get_tasks(self): """Return tasks and full_refresh flag. If there are non-initialized user found only those will be selected. If none are found a list of the user with the most new games are returned. """ async with self.db.get_connection() as db: full_refresh = await db.fetch(""" SELECT account_id, wins, losses FROM %s.summoner WHERE wins_last_updated IS NULL AND account_id IS NOT NULL ORDER BY (wins + losses) DESC LIMIT 2000; """ % self.server.lower()) if len(full_refresh) >= 100: self.logging.info("Found %s full refresh tasks." % len(full_refresh)) return full_refresh, True partial_refresh = await db.fetch( """ SELECT account_id, wins, losses, wins_last_updated, losses_last_updated FROM %s.summoner WHERE wins_last_updated IS NOT NULL AND account_id IS NOT NULL AND (wins + losses - wins_last_updated - losses_last_updated) >= $1 ORDER BY (wins + losses - wins_last_updated - losses_last_updated) DESC LIMIT 2000; """ % self.server.lower(), self.min_matches, ) self.logging.info("Found %s partial refresh tasks." % len(partial_refresh)) return partial_refresh, False async def run(self): await self.init() while not self.stopped: # Drop timed out tasks limit = int( (datetime.utcnow() - timedelta(minutes=10)).timestamp()) async with self.redis.get_connection() as buffer: await buffer.zremrangebyscore("%s_match_history_in_progress" % self.server, max=limit) # Check remaining buffer size if (size := await buffer.zcard( "%s_match_history_tasks" % self.server)) >= 1000: await asyncio.sleep(10) continue result, full_refreshes = await self.get_tasks() if not result: self.logging.info("No tasks found.") await asyncio.sleep(60) continue # Add new tasks self.logging.info("%s tasks remaining.", size) for entry in result: # Each entry will always be refered to by account_id if await buffer.zscore( "%s_match_history_in_progress" % self.server, entry["account_id"], ): continue if full_refreshes: z_index = 9999 package = { key: entry[key] for key in ["wins", "losses"] } else: z_index = (entry["wins"] + entry["losses"] - entry["wins_last_updated"] - entry["losses_last_updated"]) package = { key: entry[key] for key in [ "wins", "losses", "wins_last_updated", "losses_last_updated", ] } # Insert task hook await buffer.zadd( "%s_match_history_tasks" % self.server, z_index, entry["account_id"], ) # Insert task hash await buffer.hmset_dict( "%s:%s:%s" % (self.server, entry["account_id"], z_index), package, ) self.logging.info( "Filled tasks to %s.", await buffer.zcard("%s_match_history_tasks" % self.server), ) await asyncio.sleep(5)
class Service: """Core service worker object.""" queues = None def __init__(self): """Initiate sync elements on creation.""" self.logging = logging.getLogger("MatchDetails") level = logging.INFO self.logging.setLevel(level) handler = logging.StreamHandler() handler.setLevel(level) handler.setFormatter( logging.Formatter("%(asctime)s [MatchDetails] %(message)s")) self.logging.addHandler(handler) self.rune_ids = get_ids() self.rune_tree = get_trees() self.server = os.environ["SERVER"] self.batch_size = int(os.environ["BATCH_SIZE"]) self.redis = RedisConnector() self.db = PostgresConnector(user=self.server.lower()) self.db.set_prepare(self.prepare) self.stopped = False self.retry_after = datetime.now() self.url = (f"http://{self.server.lower()}.api.riotgames.com/lol/" + "match/v4/matches/%s") self.buffered_elements = ( {} ) # Short term buffer to keep track of currently ongoing requests self.active_tasks = [] def shutdown(self): """Called on shutdown init.""" self.stopped = True async def prepare(self, conn): template = (""" INSERT INTO %s.team (match_id, timestamp, win, side, bans, tower_kills, inhibitor_kills, first_tower, first_rift_herald, first_dragon, first_baron, rift_herald_kills, dragon_kills, baron_kills) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) ON CONFLICT DO NOTHING; """ % self.server.lower()) self.team_insert = await conn.prepare(template) template = (""" INSERT INTO %s.participant (match_id, timestamp, win, participant_id, summoner_id, summoner_spell, rune_main_tree, rune_sec_tree, rune_main_select, rune_sec_select, -- 10 rune_shards, item, trinket, champ_level, champ_id, kills, deaths, assists, gold_earned, neutral_minions_killed, neutral_minions_killed_enemy, neutral_minions_killed_team, total_minions_killed, vision_score, vision_wards_bought, wards_placed, wards_killed, physical_taken, magical_taken, true_taken, damage_mitigated, physical_dealt, magical_dealt, true_dealt, turret_dealt, objective_dealt, total_heal, total_units_healed, time_cc_others, total_cc_dealt) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11,$12,$13,$14,$15,$16,$17,$18,$19,$20, $21,$22,$23,$24,$25,$26,$27,$28,$29,$30, $31,$32,$33,$34,$35,$36,$37,$38, $39, $40) ON CONFLICT DO NOTHING """ % self.server.lower()) self.participant_insert = await conn.prepare(template) self.match_update = await conn.prepare(""" UPDATE %s.match SET duration = $1, win = $2, details_pulled = TRUE WHERE match_id = $3 """ % self.server.lower()) async def flush_manager(self, match_details): """Update entries in postgres once enough tasks are done.""" try: match_ids = [] for match in match_details: match_ids.append(match[0]) async with self.db.get_connection() as db: existing_ids = [ match["match_id"] for match in await db.fetch(""" SELECT DISTINCT match_id FROM %s.team WHERE match_id IN (%s); """ % (self.server.lower(), ",".join(match_ids))) ] team_sets = [] participant_sets = [] update_sets = [] for match in match_details: if not match[1]: continue if match[0] in existing_ids: continue details = match[1] # Team Details update_sets.append(( details["gameDuration"], details["teams"][0]["win"] == "Win", int(match[0]), )) for team in details["teams"]: bans = [ban["championId"] for ban in team["bans"]] team_sets.append(( int(match[0]), datetime.fromtimestamp(details["gameCreation"] // 1000), team["win"] == "Win", team["teamId"] == 200, bans, team["towerKills"], team["inhibitorKills"], team["firstTower"], team["firstRiftHerald"], team["firstDragon"], team["firstBaron"], team["riftHeraldKills"], team["dragonKills"], team["baronKills"], )) participants = {} for entry in details["participants"]: participants[entry["participantId"]] = entry for entry in details["participantIdentities"]: participants[entry["participantId"]].update(entry) for participant in participants.values(): try: participant_sets.append(( int(match[0]), datetime.fromtimestamp(details["gameCreation"] // 1000), details["teams"][participant["participantId"] // 6]["win"] == "Win", participant["participantId"], participant["player"]["summonerId"], [participant["spell1Id"], participant["spell2Id"]], self.rune_tree[participant["stats"]["perk0"]], self.rune_tree[participant["stats"]["perk4"]], self.rune_ids[participant["stats"]["perk0"]] + self.rune_ids[participant["stats"]["perk1"]] + self.rune_ids[participant["stats"]["perk2"]] + self.rune_ids[participant["stats"]["perk3"]], self.rune_ids[participant["stats"]["perk4"]] + self.rune_ids[participant["stats"]["perk5"]], shard_id[participant["stats"]["statPerk0"]] * 100 + shard_id[participant["stats"]["statPerk1"]] * 10 + shard_id[participant["stats"]["statPerk2"]], [ participant["stats"]["item0"], participant["stats"]["item1"], participant["stats"]["item2"], participant["stats"]["item3"], participant["stats"]["item4"], participant["stats"]["item5"], ], participant["stats"]["item6"], participant["stats"]["champLevel"], participant["championId"], participant["stats"]["kills"], participant["stats"]["deaths"], participant["stats"]["assists"], participant["stats"]["goldEarned"], participant["stats"]["neutralMinionsKilled"], participant["stats"] ["neutralMinionsKilledEnemyJungle"], participant["stats"] ["neutralMinionsKilledTeamJungle"], participant["stats"]["totalMinionsKilled"], participant["stats"]["visionScore"], participant["stats"]["visionWardsBoughtInGame"], participant["stats"]["wardsPlaced"], participant["stats"]["wardsKilled"], participant["stats"]["physicalDamageTaken"], participant["stats"]["magicalDamageTaken"], participant["stats"]["trueDamageTaken"], participant["stats"]["damageSelfMitigated"], participant["stats"] ["physicalDamageDealtToChampions"], participant["stats"] ["magicDamageDealtToChampions"], participant["stats"]["trueDamageDealtToChampions"], participant["stats"]["damageDealtToTurrets"], participant["stats"]["damageDealtToObjectives"], participant["stats"]["totalHeal"], participant["stats"]["totalUnitsHealed"], participant["stats"]["timeCCingOthers"], participant["stats"]["totalTimeCrowdControlDealt"], )) except Exception as err: self.logging.info(int(match[0])) raise err if team_sets: lines = [] async with self.db.get_connection() as db: await self.team_insert.executemany(team_sets) if participant_sets: template = await format_queue(participant_sets[0]) lines = [] for line in participant_sets: lines.append(template % tuple([ str(param) if type(param) in (list, bool) else param for param in line ])) values = ",".join(lines) async with self.db.get_connection() as db: await self.participant_insert.executemany(participant_sets) if update_sets: async with self.db.get_connection() as db: await self.match_update.executemany(update_sets) self.logging.info("Inserted %s match_details.", len(update_sets)) except Exception as err: traceback.print_tb(err.__traceback__) self.logging.info(err) async def get_task(self): """Return tasks to the async worker.""" async with self.redis.get_connection() as buffer: if not (tasks := await buffer.spop( "%s_match_details_tasks" % self.server, self.batch_size)): return tasks if self.stopped: return start = int(datetime.utcnow().timestamp()) for entry in tasks: await buffer.zadd("%s_match_details_in_progress" % self.server, start, entry) return tasks