Как я могу получить доступ к redis в крученом заводском методе? - PullRequest
0 голосов
/ 02 сентября 2018

Я использую Redis для отслеживания всех подключенных клиентов / устройств. Сервер сокетов написан с использованием Twisted. Поскольку состояние redis должно быть инициализировано перед запуском сокет-сервера, и синхронизировано после получения сигнала TERM от ОС. Я хотел бы реализовать два заводских метода.

Я попытался реализовать код следующим образом. но не удалось.

import txredisapi as redis
from twisted.internet import defer

conf = EpicConf().loadConf()
dbid = string.atoi(conf['Redisdbid'])
rcs =  redis.lazyConnection(password=conf['RedisPassword'], dbid=dbid, reconnect=True)
dbpool = adbapi.ConnectionPool("MySQLdb",db=conf['DbName'],user=conf['DbAccount'],\
        passwd=conf['DbPassword'],host=conf['DbHost'],\
        use_unicode=True,charset=conf['DbCharset'],cp_reconnect=True)

class PlainTCP(protocol.Protocol, TimeoutMixin):
    global conf

    def __init__(self, factory):
        self.factory = factory

class PlainTCPFactory(protocol.Factory):
    global conf
    onlineDevices = 'GlinkOnlineDevices'
    timezone = 8 # for CST +8

    def __init__(self):
        global conf
        print "Info: Version={}, TimeOutIdle={}".format(__version__, conf['TimeOutIdle'])

    def buildProtocol(self, addr):
        return PlainTCP(self)

    #@defer.inlineCallbacks
    def startFactory(self):
        #global rcs
        print "beforeRunning(): clean redis for running"
        #yield rcs.delete(self.onlineDevices)

    #@defer.inlineCallbacks
    def stopFactory(self):
        #global rcs
        print "afterRunning(): load from redis for logging"
        #yield rcs.delete(self.onlineDevices)

def main():
    #or another init redis operations here
    reactor.listenTCP(6000, PlainTCPFactory(), interface="0.0.0.0")
    reactor.run
    #or another sync redis operations here

if __name__ == "__main__":
    main()

Из фрагмента кода видно, что я пытался добавить код двумя фабричными методами:

  • startFactory ()
  • stopFactory ()

Но @ defer.inlinecallbacks и yield будут выдавать ошибки следующим образом, если я раскомментирую startFactory ():

        Traceback (most recent call last):
          File "/usr/local/lib/python2.7/dist-packages/Twisted-15.0.0-py2.7-linux-i686.egg/twisted/internet/defer.py", line 1107, in _inlineCallbacks
            result = g.send(result)
          File "EpicGlinkTcpServer.py", line 887, in startFactory
            yield rcs.delete(self.onlineDevices)
          File "/usr/local/lib/python2.7/dist-packages/txredisapi-1.2-py2.7.egg/txredisapi.py", line 1698, in wrapper
            d = self._factory.getConnection()
          File "/usr/local/lib/python2.7/dist-packages/Twisted-15.0.0-py2.7-linux-i686.egg/twisted/internet/defer.py", line 1253, in unwindGenerator
            return _inlineCallbacks(None, gen, Deferred())
        --- <exception caught here> ---
          File "/usr/local/lib/python2.7/dist-packages/Twisted-15.0.0-py2.7-linux-i686.egg/twisted/internet/defer.py", line 1107, in _inlineCallbacks
            result = g.send(result)
          File "/usr/local/lib/python2.7/dist-packages/txredisapi-1.2-py2.7.egg/txredisapi.py", line 2037, in getConnection
            raise ConnectionError("Not connected")
        txredisapi.ConnectionError: Not connected

И выбросить следующие ошибки, если я раскомментирую stopFactory ().

2018-09-02 16:11:24+0800 [BaseRedisProtocol,client] <twisted.internet.tcp.Connector instance at 0x9951e2c> will retry in 2 seconds
2018-09-02 16:11:24+0800 [BaseRedisProtocol,client] Stopping factory <txredisapi.RedisFactory instance at 0x9951dac>
2018-09-02 16:11:24+0800 [__main__.PlainTCPFactory] (TCP Port 6000 Closed)
2018-09-02 16:11:24+0800 [__main__.PlainTCPFactory] Stopping factory <__main__.PlainTCPFactory instance at 0x9962aac>
2018-09-02 16:11:24+0800 [__main__.PlainTCPFactory] afterRunning(): load from redis for logging
2018-09-02 16:11:24+0800 [__main__.PlainTCPFactory] Unhandled error in Deferred:
2018-09-02 16:11:24+0800 [__main__.PlainTCPFactory] Unhandled Error
        Traceback (most recent call last):
          File "/usr/local/lib/python2.7/dist-packages/Twisted-15.0.0-py2.7-linux-i686.egg/twisted/internet/defer.py", line 1107, in _inlineCallbacks
            result = g.send(result)
          File "EpicGlinkTcpServer.py", line 893, in stopFactory
            yield rcs.delete(self.onlineDevices)
          File "/usr/local/lib/python2.7/dist-packages/txredisapi-1.2-py2.7.egg/txredisapi.py", line 1698, in wrapper
            d = self._factory.getConnection()
          File "/usr/local/lib/python2.7/dist-packages/Twisted-15.0.0-py2.7-linux-i686.egg/twisted/internet/defer.py", line 1253, in unwindGenerator
            return _inlineCallbacks(None, gen, Deferred())
        --- <exception caught here> ---
          File "/usr/local/lib/python2.7/dist-packages/Twisted-15.0.0-py2.7-linux-i686.egg/twisted/internet/defer.py", line 1107, in _inlineCallbacks
            result = g.send(result)
          File "/usr/local/lib/python2.7/dist-packages/txredisapi-1.2-py2.7.egg/txredisapi.py", line 2037, in getConnection
            raise ConnectionError("Not connected")
        txredisapi.ConnectionError: Not connected

Я понятия не имею, как реализовать правильный код здесь. У меня есть еще два варианта.

  1. Добавить еще одну библиотеку synchrouns redis, независимо от текущего txredisapi, добавить два кода в main ().
  2. Добавление сценариев в сценарий внешней оболочки bash.

Однако, если кто-то может помочь мне реализовать фабричные методы. это будет прекрасно.

Заранее спасибо.

1 Ответ

0 голосов
/ 06 сентября 2018

Посмотрите на приведенный ниже пример, я думаю, что он может вам помочь.

redis.py

import txredis
from twisted.internet import protocol, reactor

REDIS = None
HOST = "localhost"
PORT = 6379

# Making connection ##############################################
def create_connection():
    client_creator = protocol.ClientCreator(reactor, txredis.RedisClient)
    df = client_creator.connectTCP(HOST, PORT)
    df.addCallback(connection_success)
    df.addErrback(cannot_connect)

# connection created
def connection_success(redis_protocol):
    global REDIS
    REDIS = redis_protocol

def cannot_connect(error):
    print(error)


def getRedis():
    global REDIS
    return REDIS

create_connection()`

main.py

from twisted.internet.protocol import ServerFactory, Protocol
from twisted.internet import reactor

from redis import getRedis


class MyProtocol(Protocol):

    def connectionMade(self):
        print(self)


class MyFactory(ServerFactory):

    protocol = MyProtocol
    onlineDevices = 'GlinkOnlineDevices'

    def __init__(self):
        pass

    def buildProtocol(self, addr):
        print(getRedis())
        p = self.protocol()
        p.factory = self
        return p

    def startFactory(self):
        def success(result):
            print(result)

        def gotError(error):
            print(error)

        redis = getRedis()
        df = redis.delete(self.onlineDevices)
        df.addCallback(success)
        df.addErrback(gotError)

    def stopFactory(self):
        redis = getRedis()

def startService():
    reactor.listenTCP(6000, MyFactory())

reactor.callLater(2, startService)
reactor.run()

Здесь я запустил фабрику через 2 секунды, чтобы установить соединение Redis до инициализации фабрики.

И для удобства я предлагаю не обращаться к объекту Redis на фабрике, вместо этого вы можете добавить необходимый класс в классе Redis, который выполняет операцию в базе данных Redis.

Надеюсь, это поможет вам.

Удачи.

...