Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tornado Example raises exception after KeyboardInterrupt #727

Open
apti-tids opened this issue Apr 3, 2016 · 5 comments
Open

Tornado Example raises exception after KeyboardInterrupt #727

apti-tids opened this issue Apr 3, 2016 · 5 comments

Comments

@apti-tids
Copy link

apti-tids commented Apr 3, 2016

I have been working through the Tornado Consumer Usage Example, however when end the example using Ctrl-C an exception is raised. I am using the following versions:

pika 0.10.0
tornado 4.3
python 3.5.1
os: Ubuntu 15.10

I have used the example as is and the only change i have made is the Rabbitmq connection information. Could you offer any guidance on where i could be going wrong. I dont get this error when i used the Asynchronous consumer example. Below is the output from running the example:

`INFO 2016-04-03 14:54:13,217 main connect 49 : Connecting to amqp://_:__@_****/%2F
INFO 2016-04-03 14:54:13,221 pika.adapters.base_connection _create_and_connect_to_socket 212 : Connecting to 192.168.1.3:25672
INFO 2016-04-03 14:54:13,276 main on_connection_open 96 : Connection opened
INFO 2016-04-03 14:54:13,279 main add_on_connection_close_callback 67 : Adding connection close callback
INFO 2016-04-03 14:54:13,281 main open_channel 307 : Creating a new channel
INFO 2016-04-03 14:54:13,286 main on_channel_open 143 : Channel opened
INFO 2016-04-03 14:54:13,286 main add_on_channel_close_callback 115 : Adding channel close callback
INFO 2016-04-03 14:54:13,287 main setup_exchange 156 : Declaring exchange message
INFO 2016-04-03 14:54:13,290 main on_exchange_declareok 168 : Exchange declared
INFO 2016-04-03 14:54:13,291 main setup_queue 179 : Declaring queue text
INFO 2016-04-03 14:54:13,293 main on_queue_declareok 193 : Binding message to text with example.text
INFO 2016-04-03 14:54:13,297 main on_bindok 290 : Queue bound
INFO 2016-04-03 14:54:13,297 main start_consuming 277 : Issuing consumer related RPC commands
INFO 2016-04-03 14:54:13,298 main add_on_cancel_callback 203 : Adding consumer cancellation callback
^CINFO 2016-04-03 14:54:15,308 main stop 329 : Stopping
INFO 2016-04-03 14:54:15,309 main stop_consuming 264 : Sending a Basic.Cancel RPC command to RabbitMQ
Traceback (most recent call last):
File "ijm_subscriber.py", line 340, in main
example.run()
File "ijm_subscriber.py", line 316, in run
self._connection.ioloop.start()
File "/home/andy/projects/python/ijm/.env/lib/python3.5/site-packages/tornado/ioloop.py", line 858, in start
event_pairs = self._impl.poll(poll_timeout)
KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "ijm_subscriber.py", line 346, in <module>
    main()
  File "ijm_subscriber.py", line 342, in main
    example.stop()
  File "ijm_subscriber.py", line 332, in stop
    self._connection.ioloop.start()
  File "/home/andy/projects/python/ijm/.env/lib/python3.5/site-packages/tornado/ioloop.py", line 748, in start
    raise RuntimeError("IOLoop is already running")
RuntimeError: IOLoop is already running`
@gmr
Copy link
Member

gmr commented Apr 4, 2016

The error is because your code on line 332 is trying to start an already running Tornado IOLoop. Try commenting out line #332.

@vitaly-krugl
Copy link
Member

@gmr: Hi Gavin, in your comment, you are referring to line 332. I don't see the user's code in this issue that this line number references. Is there an attachment somewhere that I am failing to see? Thx

@jaygorrell
Copy link

@vitaly-krugl

File "ijm_subscriber.py", line 332, in stop
self._connection.ioloop.start()
File "/home/andy/projects/python/ijm/.env/lib/python3.5/site-packages/tornado/ioloop.py", line 748, in start
raise RuntimeError("IOLoop is already running")

With that said, the Tornado Consumer example's run() method does actually call IOLoop.start(), which I'd think is a mistake since it should be running already at that point.

@vitaly-krugl
Copy link
Member

vitaly-krugl commented Apr 23, 2016

@apti-tids, indeed - there are several issues in https://github.com/pika/pika/blob/master/docs/examples/tornado_consumer.rst. I recently fixed and cleaned up the asynchronous publisher example, which had a similar structure and similar problems ( #710). This change also made that example consistent with the latest changes in pika's master branch.

In fact, there is an almost identical asynchronous consumer example that uses SelectConnection instead of TornadoConnection: https://github.com/pika/pika/blob/master/docs/examples/asynchronous_consumer_example.rst that likely suffers from the same issues.

Given that TornadoConnection and SelectConnection interfaces are virtually identical, the implementations of both consumer examples should be identical as well, differing only in the class of Connection (TornadoConnection vs. SelectConnection).

Ideally, a single asynchronous consumer implementation can be used for both adapters, if the example script simply accepted the adapter's class name (TornadoConnection or SelectConnection) as a positional command-line arg.

@apti-tids, would you be able to submit a PR that fixes both consumer examples (TornadoConnection and SelectConnection), using a single, shared implementation, referring to the changes in the asynchronous publisher example's framework (#710) as a model, where appropriate?

As part of this change, please follow this roadmap for simplicity and maintainability per DRY principle:

  1. As suggested above, create a single, functional script that accepts the asynchronous adapter name as the only positional argument ("TornadoConnection" or "SelectConnection"). Assuming the variable holding the class name in the new script is adapter_class_name, the script can load the appropriate adapter via:

    import pika
    
    def main(adapter_class_name):
        adapter_class = getattr(pika, adapter_class_name)
        conn = connectionClass(pika.URLParameters(self._url),
                               self.on_connection_open,
                               stop_ioloop_on_close=False)
    . . .
  2. Name this script async_consumer.py (or similar) and place it under pika/examples (instead of pika/docs/examples).

  3. In docs/examples/tornado_consumer.rst:

    • Replace all the code in this .rst file with something like
    async_consumer.py "pika.TornadoConnection"
    
  4. Do same with docs/examples/asynchronous_consumer_example.rst, except of course
    async_consumer.py "pika.SelectConnection"

@vitaly-krugl
Copy link
Member

vitaly-krugl commented Apr 23, 2016

There are a couple of additional benefits from placing the example scripts as actual code (versus .rst file) under pika/examples/:

  1. As you can see here, the examples tend to get out of touch with reality, because they don't get tested. I am thinking that the example python scripts should be tested as part of the CI builds. This will require some additional work in the examles to make them suitable for testing, so placing the examples in pika/examples as actual python code is the first step in that direction.
  2. Developers can run them directly, without having to copy/paste them from .rst files or web pages.

@lukebakken lukebakken added this to the 0.12.0 milestone Jul 27, 2017
@lukebakken lukebakken removed this from the 1.0.0 milestone Jan 30, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants