On 02:27 pm, [email protected] wrote:
Hello,

I've been trying to implement a simple notification system via long polling using Twisted 14.0.0. On the client side, a web page makes Ajax calls to an "update" resource, which will deliver the latest status message known to
the application. On the server side, a thread feeds a queue with status
events and another one polls this queue and sends the latest value to any pending request, trying to keep the request open for 30 seconds, or until a
new status event arrives, whichever happens sooner (this is the long
polling).

[snip]

class CounterUpdateResource(Resource):
   def __init__(self, msg_queue):
       Resource.__init__(self)
       self.msg_queue = msg_queue
       self.msg = {}
       self.etag = None
       self.pending_requests = []

       t = threading.Thread(target=self._poll_messages)
       t.daemon = True
       t.start()

   def _poll_messages(self):
       while True:
           try:
               self.msg = self.msg_queue.get(True, 30)
               self.etag = '"%s"' % (uuid.uuid4(),)
               print "-> Got new message: %s" % (self.msg,)
           except Queue.Empty:
               pass
           json_str = json.dumps(self.msg)
           json_len = len(json_str)
           while True:
               try:
                   request = self.pending_requests.pop()
                   self._actual_render(request, json_str, json_len)
               except IndexError:
                   break

   def _actual_render(self, request, json_msg, json_len):
       try:
           request.setETag(self.etag)
           request.setHeader("Content-Type", "application/json")
           request.setHeader("Content-Length", json_len)
           request.write(json_msg)
           request.finish()
       except:
           pass

`_poll_messages` is run in a thread. It calls `_actual_render` - so `_actual_render` is run in a thread. It calls these `request` methods - so they are run in a thread.

Twisted APIs are not thread-safe - except for one or two that are explicitly marked as being thread-safe.

Since this code calls Twisted APIs (the request methods) in a thread, they have undefined behavior.

If you change this so that `_actual_render` (or all of the request methods) are called in the reactor thread then I expect it will start to work reliably.

Stepping back, you might consider getting rid of the multithreaded in- process polling and instead make your application fully event-driven. Instead of having one part of your program put messages into a queue and another part look at the queue from time to time and do work if it finds an item, have one part of your program call a method implemented by another part of your program which does the work. No threads, no polling, hooray.

Stepping back even further, there are existing libraries for doing this kind of thing with Twisted already. There's Divmod Nevow's Athena and there's Minerva. There are also other approaches to "real time" web - such as websockets (see Autobahn and txwebsocket). You may not actually have to implement this low-level plumbing yourself.

Jean-Paul

_______________________________________________
Twisted-web mailing list
[email protected]
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web

Reply via email to