zmqstream.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. #
  2. # Copyright 2009 Facebook
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. """A utility class to send to and recv from a non-blocking socket,
  16. using tornado.
  17. .. seealso::
  18. - :mod:`zmq.asyncio`
  19. - :mod:`zmq.eventloop.future`
  20. """
  21. from __future__ import with_statement
  22. import sys
  23. import warnings
  24. import zmq
  25. from zmq.utils import jsonapi
  26. try:
  27. import cPickle as pickle
  28. except ImportError:
  29. import pickle
  30. from .ioloop import IOLoop, gen_log
  31. try:
  32. from tornado.stack_context import wrap as stack_context_wrap
  33. except ImportError:
  34. if "zmq.eventloop.minitornado" in sys.modules:
  35. from .minitornado.stack_context import wrap as stack_context_wrap
  36. else:
  37. # tornado 5 deprecates stack_context,
  38. # tornado 6 removes it
  39. def stack_context_wrap(callback):
  40. return callback
  41. try:
  42. from queue import Queue
  43. except ImportError:
  44. from Queue import Queue
  45. from zmq.utils.strtypes import basestring
  46. try:
  47. callable
  48. except NameError:
  49. callable = lambda obj: hasattr(obj, '__call__')
  50. class ZMQStream(object):
  51. """A utility class to register callbacks when a zmq socket sends and receives
  52. For use with zmq.eventloop.ioloop
  53. There are three main methods
  54. Methods:
  55. * **on_recv(callback, copy=True):**
  56. register a callback to be run every time the socket has something to receive
  57. * **on_send(callback):**
  58. register a callback to be run every time you call send
  59. * **send(self, msg, flags=0, copy=False, callback=None):**
  60. perform a send that will trigger the callback
  61. if callback is passed, on_send is also called.
  62. There are also send_multipart(), send_json(), send_pyobj()
  63. Three other methods for deactivating the callbacks:
  64. * **stop_on_recv():**
  65. turn off the recv callback
  66. * **stop_on_send():**
  67. turn off the send callback
  68. which simply call ``on_<evt>(None)``.
  69. The entire socket interface, excluding direct recv methods, is also
  70. provided, primarily through direct-linking the methods.
  71. e.g.
  72. >>> stream.bind is stream.socket.bind
  73. True
  74. """
  75. socket = None
  76. io_loop = None
  77. poller = None
  78. _send_queue = None
  79. _recv_callback = None
  80. _send_callback = None
  81. _close_callback = None
  82. _state = 0
  83. _flushed = False
  84. _recv_copy = False
  85. _fd = None
  86. def __init__(self, socket, io_loop=None):
  87. self.socket = socket
  88. self.io_loop = io_loop or IOLoop.current()
  89. self.poller = zmq.Poller()
  90. self._fd = self.socket.FD
  91. self._send_queue = Queue()
  92. self._recv_callback = None
  93. self._send_callback = None
  94. self._close_callback = None
  95. self._recv_copy = False
  96. self._flushed = False
  97. self._state = 0
  98. self._init_io_state()
  99. # shortcircuit some socket methods
  100. self.bind = self.socket.bind
  101. self.bind_to_random_port = self.socket.bind_to_random_port
  102. self.connect = self.socket.connect
  103. self.setsockopt = self.socket.setsockopt
  104. self.getsockopt = self.socket.getsockopt
  105. self.setsockopt_string = self.socket.setsockopt_string
  106. self.getsockopt_string = self.socket.getsockopt_string
  107. self.setsockopt_unicode = self.socket.setsockopt_unicode
  108. self.getsockopt_unicode = self.socket.getsockopt_unicode
  109. def stop_on_recv(self):
  110. """Disable callback and automatic receiving."""
  111. return self.on_recv(None)
  112. def stop_on_send(self):
  113. """Disable callback on sending."""
  114. return self.on_send(None)
  115. def stop_on_err(self):
  116. """DEPRECATED, does nothing"""
  117. gen_log.warn("on_err does nothing, and will be removed")
  118. def on_err(self, callback):
  119. """DEPRECATED, does nothing"""
  120. gen_log.warn("on_err does nothing, and will be removed")
  121. def on_recv(self, callback, copy=True):
  122. """Register a callback for when a message is ready to recv.
  123. There can be only one callback registered at a time, so each
  124. call to `on_recv` replaces previously registered callbacks.
  125. on_recv(None) disables recv event polling.
  126. Use on_recv_stream(callback) instead, to register a callback that will receive
  127. both this ZMQStream and the message, instead of just the message.
  128. Parameters
  129. ----------
  130. callback : callable
  131. callback must take exactly one argument, which will be a
  132. list, as returned by socket.recv_multipart()
  133. if callback is None, recv callbacks are disabled.
  134. copy : bool
  135. copy is passed directly to recv, so if copy is False,
  136. callback will receive Message objects. If copy is True,
  137. then callback will receive bytes/str objects.
  138. Returns : None
  139. """
  140. self._check_closed()
  141. assert callback is None or callable(callback)
  142. self._recv_callback = stack_context_wrap(callback)
  143. self._recv_copy = copy
  144. if callback is None:
  145. self._drop_io_state(zmq.POLLIN)
  146. else:
  147. self._add_io_state(zmq.POLLIN)
  148. def on_recv_stream(self, callback, copy=True):
  149. """Same as on_recv, but callback will get this stream as first argument
  150. callback must take exactly two arguments, as it will be called as::
  151. callback(stream, msg)
  152. Useful when a single callback should be used with multiple streams.
  153. """
  154. if callback is None:
  155. self.stop_on_recv()
  156. else:
  157. self.on_recv(lambda msg: callback(self, msg), copy=copy)
  158. def on_send(self, callback):
  159. """Register a callback to be called on each send
  160. There will be two arguments::
  161. callback(msg, status)
  162. * `msg` will be the list of sendable objects that was just sent
  163. * `status` will be the return result of socket.send_multipart(msg) -
  164. MessageTracker or None.
  165. Non-copying sends return a MessageTracker object whose
  166. `done` attribute will be True when the send is complete.
  167. This allows users to track when an object is safe to write to
  168. again.
  169. The second argument will always be None if copy=True
  170. on the send.
  171. Use on_send_stream(callback) to register a callback that will be passed
  172. this ZMQStream as the first argument, in addition to the other two.
  173. on_send(None) disables recv event polling.
  174. Parameters
  175. ----------
  176. callback : callable
  177. callback must take exactly two arguments, which will be
  178. the message being sent (always a list),
  179. and the return result of socket.send_multipart(msg) -
  180. MessageTracker or None.
  181. if callback is None, send callbacks are disabled.
  182. """
  183. self._check_closed()
  184. assert callback is None or callable(callback)
  185. self._send_callback = stack_context_wrap(callback)
  186. def on_send_stream(self, callback):
  187. """Same as on_send, but callback will get this stream as first argument
  188. Callback will be passed three arguments::
  189. callback(stream, msg, status)
  190. Useful when a single callback should be used with multiple streams.
  191. """
  192. if callback is None:
  193. self.stop_on_send()
  194. else:
  195. self.on_send(lambda msg, status: callback(self, msg, status))
  196. def send(self, msg, flags=0, copy=True, track=False, callback=None, **kwargs):
  197. """Send a message, optionally also register a new callback for sends.
  198. See zmq.socket.send for details.
  199. """
  200. return self.send_multipart([msg], flags=flags, copy=copy, track=track, callback=callback, **kwargs)
  201. def send_multipart(self, msg, flags=0, copy=True, track=False, callback=None, **kwargs):
  202. """Send a multipart message, optionally also register a new callback for sends.
  203. See zmq.socket.send_multipart for details.
  204. """
  205. kwargs.update(dict(flags=flags, copy=copy, track=track))
  206. self._send_queue.put((msg, kwargs))
  207. callback = callback or self._send_callback
  208. if callback is not None:
  209. self.on_send(callback)
  210. else:
  211. # noop callback
  212. self.on_send(lambda *args: None)
  213. self._add_io_state(zmq.POLLOUT)
  214. def send_string(self, u, flags=0, encoding='utf-8', callback=None, **kwargs):
  215. """Send a unicode message with an encoding.
  216. See zmq.socket.send_unicode for details.
  217. """
  218. if not isinstance(u, basestring):
  219. raise TypeError("unicode/str objects only")
  220. return self.send(u.encode(encoding), flags=flags, callback=callback, **kwargs)
  221. send_unicode = send_string
  222. def send_json(self, obj, flags=0, callback=None, **kwargs):
  223. """Send json-serialized version of an object.
  224. See zmq.socket.send_json for details.
  225. """
  226. if jsonapi is None:
  227. raise ImportError('jsonlib{1,2}, json or simplejson library is required.')
  228. else:
  229. msg = jsonapi.dumps(obj)
  230. return self.send(msg, flags=flags, callback=callback, **kwargs)
  231. def send_pyobj(self, obj, flags=0, protocol=-1, callback=None, **kwargs):
  232. """Send a Python object as a message using pickle to serialize.
  233. See zmq.socket.send_json for details.
  234. """
  235. msg = pickle.dumps(obj, protocol)
  236. return self.send(msg, flags, callback=callback, **kwargs)
  237. def _finish_flush(self):
  238. """callback for unsetting _flushed flag."""
  239. self._flushed = False
  240. def flush(self, flag=zmq.POLLIN|zmq.POLLOUT, limit=None):
  241. """Flush pending messages.
  242. This method safely handles all pending incoming and/or outgoing messages,
  243. bypassing the inner loop, passing them to the registered callbacks.
  244. A limit can be specified, to prevent blocking under high load.
  245. flush will return the first time ANY of these conditions are met:
  246. * No more events matching the flag are pending.
  247. * the total number of events handled reaches the limit.
  248. Note that if ``flag|POLLIN != 0``, recv events will be flushed even if no callback
  249. is registered, unlike normal IOLoop operation. This allows flush to be
  250. used to remove *and ignore* incoming messages.
  251. Parameters
  252. ----------
  253. flag : int, default=POLLIN|POLLOUT
  254. 0MQ poll flags.
  255. If flag|POLLIN, recv events will be flushed.
  256. If flag|POLLOUT, send events will be flushed.
  257. Both flags can be set at once, which is the default.
  258. limit : None or int, optional
  259. The maximum number of messages to send or receive.
  260. Both send and recv count against this limit.
  261. Returns
  262. -------
  263. int : count of events handled (both send and recv)
  264. """
  265. self._check_closed()
  266. # unset self._flushed, so callbacks will execute, in case flush has
  267. # already been called this iteration
  268. already_flushed = self._flushed
  269. self._flushed = False
  270. # initialize counters
  271. count = 0
  272. def update_flag():
  273. """Update the poll flag, to prevent registering POLLOUT events
  274. if we don't have pending sends."""
  275. return flag & zmq.POLLIN | (self.sending() and flag & zmq.POLLOUT)
  276. flag = update_flag()
  277. if not flag:
  278. # nothing to do
  279. return 0
  280. self.poller.register(self.socket, flag)
  281. events = self.poller.poll(0)
  282. while events and (not limit or count < limit):
  283. s,event = events[0]
  284. if event & zmq.POLLIN: # receiving
  285. self._handle_recv()
  286. count += 1
  287. if self.socket is None:
  288. # break if socket was closed during callback
  289. break
  290. if event & zmq.POLLOUT and self.sending():
  291. self._handle_send()
  292. count += 1
  293. if self.socket is None:
  294. # break if socket was closed during callback
  295. break
  296. flag = update_flag()
  297. if flag:
  298. self.poller.register(self.socket, flag)
  299. events = self.poller.poll(0)
  300. else:
  301. events = []
  302. if count: # only bypass loop if we actually flushed something
  303. # skip send/recv callbacks this iteration
  304. self._flushed = True
  305. # reregister them at the end of the loop
  306. if not already_flushed: # don't need to do it again
  307. self.io_loop.add_callback(self._finish_flush)
  308. elif already_flushed:
  309. self._flushed = True
  310. # update ioloop poll state, which may have changed
  311. self._rebuild_io_state()
  312. return count
  313. def set_close_callback(self, callback):
  314. """Call the given callback when the stream is closed."""
  315. self._close_callback = stack_context_wrap(callback)
  316. def close(self, linger=None):
  317. """Close this stream."""
  318. if self.socket is not None:
  319. if self.socket.closed:
  320. # fallback on raw fd for closed sockets
  321. # hopefully this happened promptly after close,
  322. # otherwise somebody else may have the FD
  323. warnings.warn(
  324. "Unregistering FD %s after closing socket. "
  325. "This could result in unregistering handlers for the wrong socket. "
  326. "Please use stream.close() instead of closing the socket directly."
  327. % self._fd,
  328. stacklevel=2,
  329. )
  330. self.io_loop.remove_handler(self._fd)
  331. else:
  332. self.io_loop.remove_handler(self.socket)
  333. self.socket.close(linger)
  334. self.socket = None
  335. if self._close_callback:
  336. self._run_callback(self._close_callback)
  337. def receiving(self):
  338. """Returns True if we are currently receiving from the stream."""
  339. return self._recv_callback is not None
  340. def sending(self):
  341. """Returns True if we are currently sending to the stream."""
  342. return not self._send_queue.empty()
  343. def closed(self):
  344. if self.socket is None:
  345. return True
  346. if self.socket.closed:
  347. # underlying socket has been closed, but not by us!
  348. # trigger our cleanup
  349. self.close()
  350. return True
  351. def _run_callback(self, callback, *args, **kwargs):
  352. """Wrap running callbacks in try/except to allow us to
  353. close our socket."""
  354. try:
  355. # Use a NullContext to ensure that all StackContexts are run
  356. # inside our blanket exception handler rather than outside.
  357. callback(*args, **kwargs)
  358. except:
  359. gen_log.error("Uncaught exception in ZMQStream callback",
  360. exc_info=True)
  361. # Re-raise the exception so that IOLoop.handle_callback_exception
  362. # can see it and log the error
  363. raise
  364. def _handle_events(self, fd, events):
  365. """This method is the actual handler for IOLoop, that gets called whenever
  366. an event on my socket is posted. It dispatches to _handle_recv, etc."""
  367. if not self.socket:
  368. gen_log.warning("Got events for closed stream %s", fd)
  369. return
  370. zmq_events = self.socket.EVENTS
  371. try:
  372. # dispatch events:
  373. if zmq_events & zmq.POLLIN and self.receiving():
  374. self._handle_recv()
  375. if not self.socket:
  376. return
  377. if zmq_events & zmq.POLLOUT and self.sending():
  378. self._handle_send()
  379. if not self.socket:
  380. return
  381. # rebuild the poll state
  382. self._rebuild_io_state()
  383. except Exception:
  384. gen_log.error("Uncaught exception in zmqstream callback",
  385. exc_info=True)
  386. raise
  387. def _handle_recv(self):
  388. """Handle a recv event."""
  389. if self._flushed:
  390. return
  391. try:
  392. msg = self.socket.recv_multipart(zmq.NOBLOCK, copy=self._recv_copy)
  393. except zmq.ZMQError as e:
  394. if e.errno == zmq.EAGAIN:
  395. # state changed since poll event
  396. pass
  397. else:
  398. raise
  399. else:
  400. if self._recv_callback:
  401. callback = self._recv_callback
  402. self._run_callback(callback, msg)
  403. def _handle_send(self):
  404. """Handle a send event."""
  405. if self._flushed:
  406. return
  407. if not self.sending():
  408. gen_log.error("Shouldn't have handled a send event")
  409. return
  410. msg, kwargs = self._send_queue.get()
  411. try:
  412. status = self.socket.send_multipart(msg, **kwargs)
  413. except zmq.ZMQError as e:
  414. gen_log.error("SEND Error: %s", e)
  415. status = e
  416. if self._send_callback:
  417. callback = self._send_callback
  418. self._run_callback(callback, msg, status)
  419. def _check_closed(self):
  420. if not self.socket:
  421. raise IOError("Stream is closed")
  422. def _rebuild_io_state(self):
  423. """rebuild io state based on self.sending() and receiving()"""
  424. if self.socket is None:
  425. return
  426. state = 0
  427. if self.receiving():
  428. state |= zmq.POLLIN
  429. if self.sending():
  430. state |= zmq.POLLOUT
  431. self._state = state
  432. self._update_handler(state)
  433. def _add_io_state(self, state):
  434. """Add io_state to poller."""
  435. self._state = self._state | state
  436. self._update_handler(self._state)
  437. def _drop_io_state(self, state):
  438. """Stop poller from watching an io_state."""
  439. self._state = self._state & (~state)
  440. self._update_handler(self._state)
  441. def _update_handler(self, state):
  442. """Update IOLoop handler with state."""
  443. if self.socket is None:
  444. return
  445. if state & self.socket.events:
  446. # events still exist that haven't been processed
  447. # explicitly schedule handling to avoid missing events due to edge-triggered FDs
  448. self.io_loop.add_callback(lambda : self._handle_events(self.socket, 0))
  449. def _init_io_state(self):
  450. """initialize the ioloop event handler"""
  451. self.io_loop.add_handler(self.socket, self._handle_events, self.io_loop.READ)