Thanks again Bob. Yes, ack’ing immediately neatly avoids the whole thread-safety issue by finishing the communication with the broker before spawning another thread. Unfortunately that is not a solution available to me…
I’m starting to answer my own questions now, so I’ll record them here for posterity. My new understanding of the world is:
* Kombu, via PyAMQP, is normally synchronous; calls that expect a result will block until it arrives. There’s no concept of threads or concurrency built in.
* There is an experimental asynchronous hub that lets you consume without blocking, giving you concurrent reads. It is single-threaded and implemented as callbacks. So again there is no consideration for threaded usage or concurrency of anything other than consuming (all other operations remain blocking).
* You can use a library like eventlet to make synchronous operations like those in PyAMQP appear to be concurrent, but you have to be careful not to break any assumptions based on blocking operation. For example, in eventlet writing to a socket is not an atomic operation - your thread can be swapped out for another one mid-write. If that other thread also writes to the socket, the messages become interleaved (and therefore garbage). This is a general eventlet problem and nothing to do with PyAMQP, except that it doesn’t allow for itself to be safely used by threads (e.g. by locking around operations on shared objects, like a socket). As far as I’m aware none of the Python AMQP libraries do except
http://amqpy.readthedocs.org.
Incidentally the thing that made me wonder about thread-safety in kombu at all was the following sentence in the docs for the ConsumerMixin: “It can be used outside of threads, with threads, or greenthreads (eventlet/gevent) too.” I guess that means you can put a consumer inside a thread if you want to, but nothing more.