2

I have a threaded smtp server that takes an additional 20 seconds to stop on Linux (ubuntu 14.04 and fedora 20) than it does on OS x (10.8).

from email.parser import Parser
from smtpd import SMTPServer as StdLibSmtpServer
from smtplib import SMTP
from threading import Thread
import asyncore
import re
import select
import logging
import os.path
import datetime
import json
import random
from socket import gethostname
class SmtpServer(StdLibSmtpServer, object):
    def __init__(self, listen='localhost', port=10025,
            forward_address='localhost', forward_port=10026):
        super(SmtpServer, self).__init__((listen, port), None)
        self.forward_address = forward_address
        self.forward_port = forward_port
        self._thread = None
        self._smtp = SMTP()
        self._should_re_raise_exceptions = False
    def start(self):
        if self._thread:
            raise Exception("Already running")
        logging.debug("Starting up")
        self._thread = Thread(target=self._thread_func)
        self._thread.daemon = True
        self._thread.start()
        logging.info("Started")
    def stop(self):
        if not self._thread:
            raise Exception("Not running")
        logging.debug("Stopping")
        self.close()
        self._thread.join()
        self._thread = None
        logging.info("Stopped")
    def _thread_func(self):
        try:
            asyncore.loop()
        except select.error:
            pass # socket was closed, we are shutting down

It happens at the self._thread.join() line, and I can seem to figure out why.

Any advice on how to troubleshoot this further? I run the file by doing:

from test import SmtpServer
serv = SmtpServer()
serv.start()
serv.stop()

The serv.stop() is the part that is way slower on linux.

jasonamyers
  • 1,281
  • 1
  • 9
  • 11
  • 1
    Try setting a timeout value to `self._thread.join()` — i.e. `self._thread.join(timeout=0.5);` – l'L'l Sep 15 '14 at 01:24

1 Answers1

1

It turns that the root cause was the asyncore.loop() needing to have a timeout set on systems that use select instead of epoll. Huge thanks to @binarydud for helping with this. It turns out that setting a short timeout on the thread.join works as well, but it could cause the asyncore to be orphanded.

jasonamyers
  • 1,281
  • 1
  • 9
  • 11