2012-08-30 2 views
2

이것은 이전에 대답 한 질문과 관련이 있습니다. Logging SMTP connections with Twisted. ConsoleMessageDelivery의 각 인스턴스에서 데이터베이스 리소스를 만들면 소켓을 닫을 때 정리해야합니다. DenyFactory라는 WrappingFactory가 있고 DenyFactory.unregisterProtocol 메서드는 소켓을 닫을 때 호출되지만 파괴되는 ConsoleMessageDelivery 인스턴스에서 생성 된 리소스에 액세스하는 방법이 없습니다. ConsoleMessageDelivery에서 del() 메서드를 시도했지만 결코 호출되지 않았습니다. 이 시나리오에서 리소스를 정리하는 가장 좋은 방법은 무엇입니까?Twisted Python의 SMTP 모듈을 사용한 리소스 정리

class ConsoleMessageDelivery: 
    implements(smtp.IMessageDelivery) 

    def receivedHeader(self, helo, origin, recipients): 
     myHostname, clientIP = helo 
     headerValue = "by %s from %s with ESMTP ; %s" % (myHostname, clientIP, smtp.rfc822date()) 
     # email.Header.Header used for automatic wrapping of long lines 
     return "Received: %s" % Header(headerValue) 

    def validateFrom(self, helo, origin): 
     # All addresses are accepted 
     return origin 

    def validateTo(self, user): 
     if user.dest.local == "console": 
      return lambda: ConsoleMessage() 
     raise smtp.SMTPBadRcpt(user) 

class ConsoleMessage: 
    implements(smtp.IMessage) 

    def __init__(self): 
     self.lines = [] 

    def lineReceived(self, line): 
     self.lines.append(line) 

    def eomReceived(self): 
     return defer.succeed(None) 

    def connectionLost(self): 
     # There was an error, throw away the stored lines 
     self.lines = None 

class ConsoleSMTPFactory(smtp.SMTPFactory): 
    protocol = smtp.ESMTP 

    def __init__(self, *a, **kw): 
     smtp.SMTPFactory.__init__(self, *a, **kw) 
     self.delivery = ConsoleMessageDelivery() 

    def buildProtocol(self, addr): 
     p = smtp.SMTPFactory.buildProtocol(self, addr) 
     p.delivery = self.delivery 
     return p 

class DenyFactory(WrappingFactory): 

    def buildProtocol(self, clientAddress): 
     if clientAddress.host == '1.3.3.7': 
      # Reject it 
      return None 
     # Accept everything else 
     return WrappingFactory.buildProtocol(self, clientAddress) 

    def unregisterProtocol(self, p): 
     print "Unregister called" 
+0

삭제하려는 리소스는 무엇입니까? 그것은 ConsoleMessage()가 lambda에서 생성 된 것입니까? 쓰레기 수거가 아닌지 어떻게 확신합니까? ConsoleMessageDelivery에 대한 __del__ 메소드가 호출되지 않는다면, 실제 문제는 그 객체가 결코 가비지 수집되지 않는다는 것입니다. –

+0

ConsoleMessageDelivery의 생성자에서 다른 것들과 함께 데이터베이스 연결을 여는 객체를 인스턴스화합니다. SMTP 연결이 닫히면 리소스 부족을 막기 위해 데이터베이스 연결도 닫아야합니다. 흥미롭게도 위의 DenyFactory 같은 랩핑 팩토리를 사용하지 않고 TimeoutFactory도 사용하면 __del __() 메서드가 예상대로 호출됩니다. 포장 공장에서 누수가 될 수 있습니까? –

답변

3

특히, 정리할 리소스가있는 경우 __del__을 사용하지 마십시오. __del__은 참조주기에서 오브젝트의 가비지 콜렉션을 방지합니다. (또는 사이클의 객체 컬렉션에 임의의 순서를 지정하여 이러한 객체를 수집 할 수있는 PyPy로 전환하십시오.) 다음으로 메시지 전달 팩토리에서 데이터베이스 연결을 열거 나 연결 풀을 시작하고 모든 메시지 전달 객체간에이를 공유합니다. 이렇게하면 연결을 정리할 필요가 없습니다. 이후 메시지에 다시 사용하고 각 메시지에 대해 새 메시지를 할당하지 않으므로 누출이 없습니다.

마지막으로 트랜잭션 당 개체가 실제로 필요한 경우 IMessage 개체의 eomReceived 또는 connectionLost 구현에서 정리할 수 있습니다. SMTP 트랜잭션의 DATA 부분이 완료되면 (모든 데이터가 수신되었거나 연결이 끊어 졌기 때문에)이 메서드 중 하나가 호출됩니다. SMTP는 단일 트랜잭션에서 여러 수신자에게 메시지 배달을 지원하기 때문에 하나의 IMessageDelivery 개체 만 존재하더라도 IMessage 개체가 여러 개 참여할 수 있습니다. 따라서 메시지 개체에 대한 eomReceived/connectionLost 호출의 메시지 배달 개체에서 성공적인 validateTo 호출에 대한 호출 횟수를 카운터 매치로 유지하려고 할 수 있습니다. 각각의 동일한 전화 번호가 발생한 경우 트랜잭션이 완료됩니다.

+0

답변 해 주셔서 감사합니다. 이제는 이해하고 그에 따라 코드를 다시 작성했습니다. 나는'__del __()'이 해롭다는 것을 몰랐다. 마지막 질문이 하나 있는데, [link] (http://stackoverflow.com/questions/12217858/custom-response-to-data-with-twisted-python-smtp) 그런 다음 머리에서 벗어나려고 노력할 것입니다. . :) –

+0

사실, 이미 그 답변 : 진 폴은 당신에게 더 나은 대답을 줄지 모르지만. –

관련 문제