返回目录


Twisted服务器开发技巧(3) - 动态配置加载

1. Twisted服务器开发技巧(3) - 动态配置加载

我们经常去做配置文件的更改,BSDer们常常需要在配置文件更改后重新启动daemon。这样的服务很多,比如apache。有一天我忽然羡慕起破烂的tomcat来,原因很简单,它的配置文件更改后,不再需要我去重新启动它了。其实,你只需要在性能和功能间寻找一个平衡点,所有的功能都能做到,只是你是否考虑负载的能力。twisted考虑到了动态加载这样的功能,就是在指定的时间去做一件事,但是为了让这样的功能不去影响性能,最好的办法是将这样的时间调度不使用阻塞的sleep,而使用事件的queue再进行调度。

以下是一个示例,只为运行,最终的代码肯定不会有这么糟糕的使用方法:

   1 from twisted.application import internet, service
   2 from twisted.internet import protocol, reactor, defer
   3 from twisted.protocols import basic
   4 
   5 class FingerProtocol(basic.LineReceiver):
   6     def lineReceived(self, user):
   7         self.factory.getUser(user
   8         ).addErrback(lambda _: "Internal error in server"
   9         ).addCallback(lambda m:
  10                       (self.transport.write(m+"\r\n"),
  11                        self.transport.loseConnection()))
  12 
  13 class FingerService(service.Service):
  14     def __init__(self, filename):
  15         self.users = {}
  16         self.filename = filename
  17     def _read(self):
  18         for line in file(self.filename):
  19             user, status = line.split(':', 1)
  20             user = user.strip()
  21             status = status.strip()
  22             self.users[user] = status
  23         self.call = reactor.callLater(30, self._read)
  24     def startService(self):
  25         self._read()
  26         service.Service.startService(self)
  27     def stopService(self):
  28         service.Service.stopService(self)
  29         self.call.cancel()
  30     def getUser(self, user):
  31         return defer.succeed(self.users.get(user, "No such user"))
  32     def getFingerFactory(self):
  33         f = protocol.ServerFactory()
  34         f.protocol, f.getUser = FingerProtocol, self.getUser
  35         return f
  36 
  37 application = service.Application('finger', uid=1000, gid=1)
  38 f = FingerService('/etc/users')
  39 finger = internet.TCPServer(79, f.getFingerFactory())
  40 
  41 finger.setServiceParent(service.IServiceCollection(application))
  42 f.setServiceParent(service.IServiceCollection(application))

这段代码主要是说明了factory的深入使用。init方法中只是初始化好了变量。这个与我们以前的使用没有什么两样,但是在startService和stopService中加了两句话。

self._read()

调用了_read()方法,它初始的读了/etc/users文件到内存变量中。并使用

self.call = reactor.callLater(30, self._read)

向核心调度器加入了30秒后再执行本方法。从而达到了循环不间断的调用_read方法。

而stopService中的

self.call.cancel()

语句,则在停止服务器,从核心调度器的queue中取消了本方法的调用。

准确的说,如果你希望为服务加入一系列的基本的固定周期的事务,哪么使用这样的技巧来将它们加入到核心调度器中去罢。而不要启动单独的线程加入sleep来操作,要知道twisted会更有效的使用调度机制,损耗只会更小。


返回目录