说明

昨天下午有同事反映运维平台权限加上去后,但实际没生效,当时简单瞧了一下数据库生效了,但Redis没同步,权限添加到mysql然后会同刷一次Redis。没刷成功,当时由于在忙Ansible API的一些东西,没急着弄。

寻找问题

实际调用类

class Permission(DbBase):
    '''权限认证类操作'''
    def __init__(self):
        """权限认证类
        :rtype: object
        """
        super(Permission, self).__init__()
        self.SESSION_NAME = conf.SESSION_NAME
                .....

父类DbBase

需要注意的是这里并没有走继承方法,而是会每次都初始化,当时想的是要继承两个类,所以用实际方法写,这个先不管。有问题后面再改。

class DbBase(object):
    '''数据库基类操作'''
    def __init__(self):
        self.mysql = db.Mysql() # instance mysql object
        self.redis = db.Redis() # instance redis object

        '''Call Mysql Object  methods'''
        self._db_write = self.mysql.write
        self._db_fetchone = self.mysql.fetchone
        self._db_fetchall = self.mysql.fetchall

        '''Redis Users Session key'''
        self.session_key = "----"

基类

class Redis():
    def __init__(self):
        parmas = {
            'host' : conf.REDIS_HOST,
            'port' : conf.REDIS_PORT,
            'password' : conf.REDIS_PASS,
        }
        # 改一下方法, ttl一直获取为-2
        self.cursor = redis.Redis(**parmas)

查看代码

1

class Redis(StrictRedis):
    """
    Provides backwards compatibility with older versions of redis-py that
    changed arguments to some commands to be more Pythonic, sane, or by
    accident.
    """

2

看到长连接参数socket_keepalive,看看代码。

class StrictRedis(object):
                def __init__(self, host='localhost', port=6379,
                 db=0, password=None, socket_timeout=None,
                 socket_connect_timeout=None,
                 socket_keepalive=None, socket_keepalive_options=None,
                 connection_pool=None, unix_socket_path=None,
                 encoding='utf-8', encoding_errors='strict',
                 charset=None, errors=None,
                 decode_responses=False, retry_on_timeout=False,
                 ssl=False, ssl_keyfile=None, ssl_certfile=None,
                 ssl_cert_reqs=None, ssl_ca_certs=None,
                 max_connections=None):

3

最终定位到此方法,默认走的是短链接

                # TCP_KEEPALIVE
                if self.socket_keepalive:
                    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
                    for k, v in iteritems(self.socket_keepalive_options):
                        sock.setsockopt(socket.SOL_TCP, k, v)

问题推测

有可能是长短链接的问题,链接失效后再调用会出问题。

代码修改

代码有注释

'''Redis DB Object'''
class Redis():
    def __init__(self):
        # 这里的 socket_keepalive是为长链接,因为后面会很多
        # 子类继承这个类,为保持连接的长久性
        parmas = {
            'host' : conf.REDIS_HOST,
            'port' : conf.REDIS_PORT,
            'password' : conf.REDIS_PASS,
            'socket_keepalive' : True,
        }
        # 改一下方法, ttl一直获取为-2
        self.cursor = redis.Redis(**parmas)

并未解决

更新代码权限操作重新初始化self.redis对象。继续测试。