Document threading limitations and show multiprocessing example.

This commit is contained in:
Stuart Gathman
2011-06-10 01:39:59 +00:00
parent f6702e39dd
commit b946759857
5 changed files with 52 additions and 15 deletions
+9 -6
View File
@@ -28,6 +28,7 @@ def uniqueID():
_seq_lock.release()
return seqno
## @private
OPTIONAL_CALLBACKS = {
'connect':(P_NR_CONN,P_NOCONNECT),
'hello':(P_NR_HELO,P_NOHELO),
@@ -40,6 +41,7 @@ OPTIONAL_CALLBACKS = {
'header':(P_NR_HDR,P_NOHDRS)
}
## @private
def decode_mask(bits,names):
t = [ (s,getattr(milter,s)) for s in names]
nms = [s for s,m in t if bits & m]
@@ -47,6 +49,13 @@ def decode_mask(bits,names):
if bits: nms += hex(bits)
return nms
## @fn set_flags(flags)
# @brief Enable optional %milter actions.
# Certain %milter actions need to be enabled before calling milter.runmilter()
# or they throw an exception.
# @param flags Bit ored mask of optional actions to enable
## Class decorator to enable optional protocol steps.
# P_SKIP is enabled by default when supported, but
# applications may wish to enable P_HDR_LEADSPC
@@ -538,12 +547,6 @@ class Milter(Base):
# change in configuration.
factory = Milter
## @fn set_flags(flags)
# @brief Enable optional %milter actions.
# Certain %milter actions need to be enabled before calling milter.runmilter()
# or they throw an exception.
# @param flags Bit ored mask of optional actions to enable
## @private
# @brief Connect context to connection instance and return enabled callbacks.
def negotiate_callback(ctx,opts):
+1 -2
View File
@@ -69,8 +69,7 @@ Not-so-quick Installation
First install Sendmail. Make sure you read libmilter/README in the Sendmail
source directory, and make sure you enable libmilter before you build. The
8.11 series had libmilter marked as FFR (For Future Release); 8.12
officially
supports libmilter, but it's still not built by default.
officially supports libmilter, but it's still not built by default.
Install Python, and enable threading in Modules/Setup.
+18 -1
View File
@@ -1,6 +1,5 @@
## @mainpage Writing Milters in Python
#
#
# At the lowest level, the <code>milter</code> module provides a thin wrapper
# around the <a href="https://www.milter.org/developers/api/index"> sendmail
# libmilter API</a>. This API lets you register callbacks for a number of
@@ -34,3 +33,21 @@
# The <code>mime</code> module provides a wrapper for the Python email package
# that fixes some bugs, and simplifies modifying selected parts of a MIME
# message.
#
# @section threading
#
# The libmilter library which pymilter wraps
# <a href="https://www.milter.org/developers/overview#SignalHandling">handles
# all signals</a> itself, and expects to be called from a single main thread.
# It handles SIGTERM, SIGHUP, and SIGINT, mapping the first two to
# <a href="https://www.milter.org/developers/api/smfi_stop">smfi_stop</a>
# and the last to an internal ABORT.
#
# If you use python threads or threading modules, then signal handling gets
# confused. Threads may still be useful, but you may need to provide an
# alternate means of causing graceful shutdown.
#
# You may find the
# <a href="http://docs.python.org/release/2.6.6/library/multiprocessing.html">
# multiprocessing</a> module useful. It can be a drop-in
# replacement for threading as illustrated in @ref milter-template.py.
+20 -4
View File
@@ -14,7 +14,13 @@ import email
import sys
from socket import AF_INET, AF_INET6
from Milter.utils import parse_addr
if True:
from multiprocessing import Process as Thread, Queue
else:
from threading import Thread
from Queue import Queue
logq = Queue(maxsize=4)
class myMilter(Milter.Base):
@@ -117,16 +123,24 @@ class myMilter(Milter.Base):
## === Support Functions ===
def log(self,*msg):
print "%s [%d]" % (time.strftime('%Y%b%d %H:%M:%S'),self.id),
logq.put((msg,self.id,time.time()))
def background():
while True:
t = logq.get()
if not t: break
msg,id,ts = t
print "%s [%d]" % (time.strftime('%Y%b%d %H:%M:%S',time.localtime(ts)),id),
# 2005Oct13 02:34:11 [1] msg1 msg2 msg3 ...
for i in msg: print i,
print
## ===
def main():
socketname = "/tmp/pythonsock"
bt = Thread(target=background)
bt.start()
socketname = "/home/stuart/pythonsock"
timeout = 600
# Register to have the Milter factory create instances of your class:
Milter.factory = myMilter
@@ -136,7 +150,9 @@ def main():
Milter.set_flags(flags) # tell Sendmail which features we use
print "%s milter startup" % time.strftime('%Y%b%d %H:%M:%S')
sys.stdout.flush()
Milter.runmilter("test",socketname,timeout)
Milter.runmilter("pythonfilter",socketname,timeout)
logq.put(None)
bt.join()
print "%s bms milter shutdown" % time.strftime('%Y%b%d %H:%M:%S')
if __name__ == "__main__":
+4 -2
View File
@@ -13,8 +13,9 @@ License: GPLv2+
Group: Development/Libraries
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
Url: http://www.bmsi.com/python/milter.html
Requires: %{pythonbase}, sendmail >= 8.13
# Need python2.4 specific pydns, not the version for system python
# python-2.6.4 gets RuntimeError: not holding the import lock
Requires: %{pythonbase} >= 2.6.5, sendmail >= 8.13
# Need python2.6 specific pydns, not the version for system python
Requires: %{pythonbase}-pydns
# Needed for callbacks, not a core function but highly useful for milters
BuildRequires: ed, %{pythonbase}-devel, sendmail-devel >= 8.13
@@ -77,6 +78,7 @@ rm -rf $RPM_BUILD_ROOT
* Wed Mar 02 2010 Stuart Gathman <stuart@bmsi.com> 0.9.5-1
- Print milter.error for invalid callback return type.
(Since stacktrace is empty, the TypeError exception is confusing.)
- Fix milter-template.py
* Wed Mar 02 2010 Stuart Gathman <stuart@bmsi.com> 0.9.4-1
- Handle IP6 in Milter.utils.iniplist()