def get_upgrade_lock(dbname, connect_str, timeout=LOCK_TIMEOUT):
    """
    Wait until you can get the lock, then yield it, and eventually release it.

    Inspired by: http://arr.gr/blog/2016/05/mysql-named-locks-in-python-context-managers/

    :param dbname: database to upgrade
    :param connect_str: connection string to the database
    :param timeout: how long to wait between tries for the lock, default 5 seconds
    """
    #
    # Open connection and try to get the lock
    #
    engine = sqlalchemy.create_engine(connect_str)
    cursor = engine.execute("SELECT GET_LOCK('upgrade_{}', {})".format(dbname, timeout))
    lock = cursor.scalar()
    cursor.close()

    #
    # Keep trying until you get it.
    #
    while not lock:
        logger.info('Cannot acquire {} upgrade lock. Sleeping {} seconds.'.format(dbname, timeout))
        time.sleep(timeout)
        cursor = engine.execute("SELECT GET_LOCK('upgrade_{}', {})".format(dbname, timeout))
        lock = cursor.scalar()
        cursor.close()
    logger.info('Acquired {} upgrade lock'.format(dbname))
    yield lock

    #
    # Release the lock and close the connection.
    #
    cursor = engine.execute("SELECT RELEASE_LOCK('upgrade_{}')".format(dbname))
    cursor.close()
    engine.dispose()
    logger.info('Released {} upgrade lock'.format(dbname))
Wait until you can get the lock, then yield it, and eventually release it.

    Inspired by: http://arr.gr/blog/2016/05/mysql-named-locks-in-python-context-managers/

    :param dbname: database to upgrade
    :param connect_str: connection string to the database
    :param timeout: how long to wait between tries for the lock, default 5 seconds