def cleanup_orphaned_matchqueues(): """ Find matches who have been reserved by the match queue but not joined for 10 minutes and make them available to other players """ logger = get_task_logger("cleanup_orphaned_matchqueues") tier_name = get_tier_name() tenants = driftbase.tasks.get_tenants() logger.info("Cleaning up match queues for %s tenants...", len(tenants)) for tenant_config in tenants: tenant_name = tenant_config["name"] if tenant_config.get("name", "*") == "*": continue try: this_conn_string = get_connection_string(tenant_config, None, tier_name=tier_name) except TenantNotFoundError: continue with sqlalchemy_session(this_conn_string) as session: sql = """ SELECT m.* FROM gs_matches m INNER JOIN gs_servers s ON s.server_id = m.server_id WHERE m.status = 'queue' AND m.status_date::timestamp < now()::timestamp - interval '5 minutes' AND s.heartbeat_date::timestamp >= now()::timestamp - interval '2 minutes' ORDER BY m.match_id DESC """ result = session.execute(sql) orphaned_matches = set() match = result.fetchone() while match: orphaned_matches.add(match.match_id) match = result.fetchone() if orphaned_matches: log.info("Tenant '%s' has %s orphaned matches", tenant_name, len(orphaned_matches)) for match_id in orphaned_matches: match = session.query(Match).get(match_id) match.status = "idle" match.status_date = utcnow() matchqueueplayers = session.query(MatchQueuePlayer) \ .filter(MatchQueuePlayer.match_id == match_id) for p in matchqueueplayers: session.delete(p) logger.info( "Cleaning up orphaned match '%s' in tenant '%s' and putting it " "back into the pool", match_id, tenant_name) session.commit() # if we cleaned up any matches we should process the match queue in # case there are any players waiting if orphaned_matches: logger.info("Processing match queue") redis = RedisCache(tenant=tenant_config["name"], redis_server=tenant_config['redis_server']) process_match_queue(redis, session)
def get_mock_tenants(): t = {"name": os.environ.get("drift_test_database"), "db_server": "localhost", "redis_server": "localhost", "heartbeat_timeout": 0, } conn_string = get_connection_string(t, None, tier_name=get_tier_name()) t["conn_string"] = conn_string return [t]
def db_check(tenant_config): from drift.tenant import get_connection_string try: conn_string = get_connection_string(tenant_config) engine = create_engine(conn_string, echo=False) engine.execute("SELECT 1=1") except Exception as e: return repr(e) return None
def tenant_report(tenant_config): from drift.tenant import get_connection_string conn_string = get_connection_string(tenant_config) print "Tenant configuration for '{}' on tier '{}':" \ .format(tenant_config["name"], get_tier_name()) for k in sorted(tenant_config.keys()): print " {} = {}".format(k, tenant_config[k]) print "Connection string:\n {}".format(conn_string) print "Database check... " db_error = db_check(tenant_config) if db_error: if "does not exist" in db_error: print Fore.RED + " FAIL! DB does not exist" print " You can create this database by running this " \ "command again with the action 'create'" else: print Fore.RED + " {}".format(db_error) else: print Fore.GREEN + " OK! Database is online and reachable"
def update_online_statistics(): """ """ logger = get_task_logger("update_statistics") tier_name = get_tier_name() config = load_config() tenants = config.get("tenants", []) logger.info("Updating statistics for %s tenants...", len(tenants)) num_updated = 0 for tenant_config in tenants: if tenant_config.get("name", "*") == "*": continue try: this_conn_string = get_connection_string(tenant_config, None, tier_name=tier_name) except TenantNotFoundError: continue with sqlalchemy_session(this_conn_string) as session: result = session.execute("""SELECT COUNT(DISTINCT(player_id)) AS cnt FROM ck_clients WHERE heartbeat > NOW() - INTERVAL '1 minutes'""") cnt = result.fetchone()[0] if cnt: num_updated += 1 tenant_name = tenant_config["name"] name = 'backend.numonline' row = session.query(Counter).filter(Counter.name == name).first() if not row: row = Counter(name=name, counter_type="absolute") session.add(row) session.commit() counter_id = row.counter_id timestamp = datetime.datetime.utcnow() add_count(counter_id, 0, timestamp, cnt, is_absolute=True, db_session=session) session.commit() print "Updated num_online for %s to %s" % (tenant_name, cnt) logger.info("Updated %s tenants with online user count", num_updated)
def get_tenants(): tier_name = get_tier_name() config = load_config() _tenants = config.get("tenants", []) tenants = [] for t in _tenants: t["heartbeat_timeout"] = config.get("heartbeat_timeout", DEFAULT_HEARTBEAT_TIMEOUT) if t.get("name", "*") == "*": continue try: this_conn_string = get_connection_string(t, None, tier_name=tier_name) except TenantNotFoundError: continue t["conn_string"] = this_conn_string if config.get("redis_server", None): t["redis_server"] = config.get("redis_server") tenants.append(t) return tenants
def get_engines(): if conn_string: engines = { "dude": { "engine": create_engine(conn_string, echo=False, poolclass=pool.NullPool), "url": conn_string } } return engines engines = {} from drift.tenant import get_connection_string config = load_config() tenants = [] pick_tenant = None if sys.argv[1] == '-x': pick_tenant = sys.argv[2] print 'picking tenant %s' % pick_tenant for tier in config["tiers"]: tier_name = tier["name"] config = load_config(tier_name) tenant_names = [] for t in config.get("tenants", []): if not t.get("db_server"): continue name = t["name"] t["tier_name"] = tier_name if not (pick_tenant and name != pick_tenant) and name != "*": tenants.append(t) tenant_names.append(name) logger.info("Gathering tenants for tier %s: %s", tier_name, (", ".join(tenant_names) or "(none)")) db_servers = set([]) for tenant_config in tenants: from drift.flaskfactory import TenantNotFoundError try: conn_info = {"user": "******", "password": "******"} this_conn_string = get_connection_string( tenant_config, conn_info, tier_name=tenant_config["tier_name"]) except TenantNotFoundError: logger.info("Tenant '{}' on tier '{}' not found".format( tenant_config["name"], tenant_config["tier_name"])) continue if this_conn_string not in [e["url"] for e in engines.itervalues()]: engines["{}.{}".format(tenant_config["tier_name"], tenant_config["name"])] = rec = { "url": this_conn_string } # quick and dirty connectivity test before trying to upgrade all db's print "Checking connectivity..." db_servers = set() for key, engine in engines.iteritems(): server = engine["url"].split("/") db_servers.add(server[2].split("@")[1].lower()) err = False for db_server in db_servers: port = 5432 sys.stdout.write(db_server + "... ") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(2) result = sock.connect_ex((db_server, port)) if result != 0: print "Unable to connect to server '%s' on port %s" % (db_server, port) err = True else: print "OK" if err: raise Exception( "Unable to connect to one or more db servers. Bailing out!") for key in engines.keys(): rec = engines[key] connection_string = rec["url"] logger.info("Connecting '{}'...".format(connection_string)) rec['engine'] = create_engine(connection_string, echo=False, poolclass=pool.NullPool) rec['url'] = connection_string return engines
def run_command(args): print from drift import tenant tenant_name = args.tenant if not tenant_name: tenants_report() return tier_name = get_tier_name() config = load_config() tenant_config = {} for tenant_config in config.get("tenants", []): if tenant_config["name"].lower() == tenant_name.lower(): # get the right casing from config tenant_name = tenant_config["name"] break else: print Fore.RED + "ERROR! Tenant '{}' is not registered in config for tier '{}'" \ .format(tenant_name, tier_name) print "Please add the tenant into config/config_{}.json and " \ "then run this command again\n".format(tier_name) return if not args.action: tenant_report(tenant_config) return db_host = tenant_config["db_server"] if ":" not in db_host: db_host += ":{}".format(POSTGRES_PORT) # TODO validation db_name = None if "recreate" in args.action: actions = ["drop", "create"] print "Recreating db for tenant '{}'".format(tenant_name) else: actions = [args.action] if "drop" in actions: print "Dropping tenant {} on {}...".format(tenant_name, db_host) db_error = db_check(tenant_config) if db_error: print "ERROR: You cannot drop the db because it is not reachable: {}".format( db_error) return else: tenant.drop_db(tenant_name, db_host, tier_name) if "create" in args.action: print "Creating tenant '{}' on server '{}'...".format( tenant_name, db_host) db_notfound_error = db_check(tenant_config) if not db_notfound_error: print "ERROR: You cannot create the database because it already exists" print "Use the command 'recreate' if you want to drop and create the db" from drift.tenant import get_connection_string conn_string = get_connection_string(tenant_config) print "conn_string = " + conn_string else: tenant.create_db(tenant_name, db_host, tier_name) tenant_report(tenant_config)