How to pass asyncio.get_event_loop() to quart in command line? - heroku

In a doc they passed event loop to quart.
Need to call async method in route handler.
How to change this to command line for heroku?
if __name__ == '__main__':
loop=asyncio.get_event_loop()
app.run(loop=loop)
I tried
web: hypercorn -b 0.0.0.0:${PORT} --workers=1 telegram:app -k asyncio
But still got
2019-06-22 10:00:45.047703 app[web.1]: Task <Task pending coro=<ASGIWebsocketConnection.handle_websocket() running at /app/.heroku/python/lib/python3.7/site-packages/quart/asgi.py:135> cb=[_wait.<locals>._on_completion() at /app/.heroku/python/lib/python3.7/asyncio/tasks.py:440]> got Future <Future pending> attached to a different loop
2019-06-22 10:00:45.048350 app[web.1]: Traceback (most recent call last):
2019-06-22 10:00:45.048395 app[web.1]: File "/app/tele.py", line 34, in create_contact
2019-06-22 10:00:45.048399 app[web.1]: contacts =await client2(functions.contacts.ImportContactsRequest([contact]))
2019-06-22 10:00:45.048410 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/telethon/client/users.py", line 60, in __call__
2019-06-22 10:00:45.048414 app[web.1]: result = await future
2019-06-22 10:00:45.048458 app[web.1]: RuntimeError: Task <Task pending coro=<ASGIWebsocketConnection.handle_websocket() running at /app/.heroku/python/lib/python3.7/site-packages/quart/asgi.py:135> cb=[_wait.<locals>._on_completion() at /app/.heroku/python/lib/python3.7/asyncio/tasks.py:440]> got Future <Future pending> attached to a different loop
Follow up question for this
How to obtain an event loop from Quart
here says quart's app.run() uses the default event loop created by asyncio for the main thread
Then why they pass the loop?

Because hypercorn will not go inside if __main__, you need to create loop beforehand and set it as default:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# do whatever you want, e.g.:
# loop.create_task(background())
if __name__ == '__main__':
loop = asyncio.get_event_loop() # now unnecessary
app.run(loop=loop)
# should be just
if __name__ == '__main__':
app.run()

Opening client inside before_serving solved this.

Related

Using Python's asyncio 'await' in ros2 callbacks: 'RuntimeError: await wasn't used with future'

I'm trying to call an asyncio async function from a ROS2 callback as seen in the code below. The callback always throws an error 'RuntimeError: await wasn't used with future' and I can't figure out why. It doesn't seem to have this error when awaiting a custom async function that doesn't await anything itself (see 'test_async()').
Minimal example
Subscriber - foo
import asyncio, rclpy
from rclpy.node import Node
from std_msgs.msg import Bool
from concurrent.futures import ThreadPoolExecutor
import rclpy.qos as qos
from rclpy.qos import QoSProfile
class Foo(Node):
def __init__(self):
super().__init__('foo')
# Setup test subscriber
qos_profile = QoSProfile(
reliability=qos.ReliabilityPolicy.BEST_EFFORT,
durability=qos.DurabilityPolicy.TRANSIENT_LOCAL,
history=qos.HistoryPolicy.KEEP_LAST,
depth=1
)
self.test_sub = self.create_subscription(
Bool,
'/foo_sub',
self.clbk,
qos_profile)
# Test callback function
async def clbk(self, msg):
self.get_logger().info(f'Received: {msg.data}. About to test async')
# This doesn't cause a problem
await self.test_async()
# This doesn't work
self.get_logger().info('About to sleep')
await asyncio.sleep(3)
# Workaround: This appears to run sleep in a separate thread.
# executor = ThreadPoolExecutor(max_workers=1)
# asyncio.get_event_loop().run_in_executor(executor, asyncio.run, asyncio.sleep(3))
# executor.shutdown(wait=True)
# The workaround doesn't work when getting a returned value
# executor = ThreadPoolExecutor(max_workers=1)
# asyncio.get_event_loop().run_in_executor(executor, asyncio.run, self.sleep_with_return())
# executor.shutdown(wait=True)
self.get_logger().info('Clbk complete')
# Working async function
async def test_async(self):
self.get_logger().info('Test async works!')
# Workaround failure case
async def sleep_with_return(self):
await asyncio.sleep(3)
return True
async def async_main():
rclpy.init()
# Create node and spin
foo = Foo()
rclpy.spin(foo)
def main():
asyncio.run(async_main())
if __name__ == '__main__':
main()
Publisher - bar
import asyncio, rclpy
from rclpy.node import Node
from std_msgs.msg import Bool
import rclpy.qos as qos
from rclpy.qos import QoSProfile
class Bar(Node):
def __init__(self):
super().__init__('bar')
# Setup test publisher
qos_profile = QoSProfile(
reliability=qos.ReliabilityPolicy.BEST_EFFORT,
durability=qos.DurabilityPolicy.TRANSIENT_LOCAL,
history=qos.HistoryPolicy.KEEP_LAST,
depth=1
)
self.test_pub = self.create_publisher(Bool, '/foo_sub', qos_profile)
def send_msg(self):
msg = Bool()
msg.data = True
self.test_pub.publish(msg)
def main():
rclpy.init()
# Create node
bar = Bar()
# Send messages
while True:
input('Press enter when you want to send msg')
bar.send_msg()
if __name__ == '__main__':
main()
Output
After running both nodes and sending a msg from bar (by pressing 'enter'), this is foo's error message:
[INFO] [1674748995.662302006] [foo]: Received: True. About to test async
[INFO] [1674748995.662621572] [foo]: Test async works!
[INFO] [1674748995.662859403] [foo]: About to sleep
Traceback (most recent call last):
File "/home/harvey/px4_ros_com_ros2/install/swarm_load_carry/lib/swarm_load_carry/foo", line 33, in <module>
sys.exit(load_entry_point('swarm-load-carry==0.0.0', 'console_scripts', 'foo')())
File "/home/harvey/px4_ros_com_ros2/install/swarm_load_carry/lib/python3.10/site-packages/swarm_load_carry/foo.py", line 74, in main
asyncio.run(async_main())
File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
return future.result()
File "/home/harvey/px4_ros_com_ros2/install/swarm_load_carry/lib/python3.10/site-packages/swarm_load_carry/foo.py", line 71, in async_main
rclpy.spin(foo)
File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/__init__.py", line 222, in spin
executor.spin_once()
File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 713, in spin_once
raise handler.exception()
File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/task.py", line 239, in __call__
self._handler.send(None)
File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 418, in handler
await call_coroutine(entity, arg)
File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 343, in _execute_subscription
await await_or_execute(sub.callback, msg)
File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 104, in await_or_execute
return await callback(*args)
File "/home/harvey/px4_ros_com_ros2/install/swarm_load_carry/lib/python3.10/site-packages/swarm_load_carry/foo.py", line 39, in clbk
await asyncio.sleep(3)
File "/usr/lib/python3.10/asyncio/tasks.py", line 605, in sleep
return await future
RuntimeError: await wasn't used with future
[ros2run]: Process exited with failure 1
As you can see in the commented out section in 'clbk', I have found a workaround by running asyncio.run in a separate thread. This is unideal however as it makes the code more complex and I can't retrieve return values (say if asyncio.sleep(3) actually returned something).
As this works, my guess is it might have something to do with asyncio not being threadsafe and ros2 callbacks running in a different thread (I can't seem to find if this is true), or something to do with where the asyncio event loop is running... I've tried may other workarounds based on this assumption however (such as getting the event loop, using call_soon_threadsafe, setting new event loops) and none seem to work.
Running process
Each node 'foo' and 'bar' are run in their own terminals with 'ros2 run pkg module' where pkg (swarm_load_carry) is the name of the ros2 package in a colcon workspace and module is either foo or bar. I am confident that the workspace, package and launchfiles are set up correctly as they work with other test cases.
System details
Ubuntu 22.04.1
Python 3.10
Ros2 Humble

How to await Tasks created inside an endless loop in asyncio

I want to create tasks programatically inside the running loop. Every second will be check if some tasks are currently not running (sometimes because of exceptions) the should be started. For simplicity reasons here ist only the loop.
import asyncio
async def parent_coro():
await child_coro()
async def child_coro():
await asyncio.sleep(1)
raise Exception('OMG!')
async def main():
tasks = []
while True:
task = asyncio.create_task(parent_coro()),
tasks.append(task)
await asyncio.sleep(1)
# This cannot be reached
done, pending = await asyncio.wait(tasks)
for task in done:
try:
print(task.exception())
except Exception:
print('You will not see me!')
if __name__ == '__main__':
asyncio.run(main())
The problem is that this Tasks cannot be awaited, and when I stop the process (Ctrl+C) I get Task exception was never retrieved. Here the stacktrace:
^CTraceback (most recent call last):
File "/tmp/check.py", line 33, in <module>
asyncio.run(main())
File "/home/antonio/.pyenv/versions/3.9.6/lib/python3.9/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/home/antonio/.pyenv/versions/3.9.6/lib/python3.9/asyncio/base_events.py", line 629, in run_until_complete
self.run_forever()
File "/home/antonio/.pyenv/versions/3.9.6/lib/python3.9/asyncio/base_events.py", line 596, in run_forever
self._run_once()
File "/home/antonio/.pyenv/versions/3.9.6/lib/python3.9/asyncio/base_events.py", line 1854, in _run_once
event_list = self._selector.select(timeout)
File "/home/antonio/.pyenv/versions/3.9.6/lib/python3.9/selectors.py", line 469, in select
fd_event_list = self._selector.poll(timeout, max_ev)
KeyboardInterrupt
Task exception was never retrieved
future: <Task finished name='Task-6' coro=<parent_coro() done, defined at /home/myproject/check.py:4> exception=Exception('OMG!')>
Traceback (most recent call last):
File "/tmp/check.py", line 5, in parent_coro
await child_coro()
File "/tmp/check.py", line 10, in child_coro
raise Exception('OMG!')
Exception: OMG!
Task exception was never retrieved
future: <Task finished name='Task-5' coro=<parent_coro() done, defined at /tmp/check.py:4> exception=Exception('OMG!')>
Traceback (most recent call last):
File "/tmp/check.py", line 5, in parent_coro
await child_coro()
File "/tmp/check.py", line 10, in child_coro
raise Exception('OMG!')
Exception: OMG!
Task exception was never retrieved
future: <Task finished name='Task-4' coro=<parent_coro() done, defined at /tmp/check.py:4> exception=Exception('OMG!')>
Traceback (most recent call last):
File "/tmp/check.py", line 5, in parent_coro
await child_coro()
File "/tmp/check.py", line 10, in child_coro
raise Exception('OMG!')
Exception: OMG!
Task exception was never retrieved
future: <Task finished name='Task-3' coro=<parent_coro() done, defined at /home/myproject/check.py:4> exception=Exception('OMG!')>
Traceback (most recent call last):
File "/home/myproject/check.py", line 5, in parent_coro
await child_coro()
File "/home/myproject/check.py", line 10, in child_coro
raise Exception('OMG!')
Exception: OMG!
Task exception was never retrieved
future: <Task finished name='Task-2' coro=<parent_coro() done, defined at /home/myproject/check.py:4> exception=Exception('OMG!')>
Traceback (most recent call last):
File "/home/myproject/check.py", line 5, in parent_coro
await child_coro()
File "/home/myproject/check.py", line 10, in child_coro
raise Exception('OMG!')
Exception: OMG!
There is now way for your code to exit the while loop.
As a solution, you can inspect your tasks inside the while loop. Your tasks will then be inspected every second.
async def main():
tasks = []
while True:
task = asyncio.create_task(parent_coro()),
tasks.append(task)
await asyncio.sleep(1)
done, pending = await asyncio.wait(tasks)
for task in done:
try:
print(task.exception())
except Exception:
print('You will not see me!)
You could also create a background task launching parent_coro tasks every second. In this case, once this task is launched, you could check tasks whenever you want.

Is there a way to call `curio.spawn` from within `asyncio.run`

There is a great library that I want to use from a larger project that I'm working on that uses "standard asyncio". Some of the functionality of the library calls curio.spawn which results in an error when called from "standard asyncio". Is there a way to get this to work?
Example code that reproduces the error:
import curio
import asyncio
async def curio_method():
await curio.sleep(1)
async def asyncio_method():
task = await curio.spawn(curio_method())
await task
asyncio.run(asyncio_method())
Result:
Traceback (most recent call last):
File "/tmp/curio_test.py", line 12, in <module>
asyncio.run(asyncio_method())
File "/usr/lib/python3.9/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/tmp/curio_test.py", line 8, in asyncio_method
task = await curio.spawn(curio_method())
File "/home/garyvdm/dev/image_builder/bpmagent/ve/lib/python3.9/site-packages/curio/task.py", line 613, in spawn
task = await _spawn(coro)
File "/home/garyvdm/dev/image_builder/bpmagent/ve/lib/python3.9/site-packages/curio/traps.py", line 83, in _spawn
return await _kernel_trap('trap_spawn', coro)
File "/home/garyvdm/dev/image_builder/bpmagent/ve/lib/python3.9/site-packages/curio/traps.py", line 32, in _kernel_trap
result = yield request
RuntimeError: Task got bad yield: ('trap_spawn', <coroutine object curio_method at 0x7fc1b62eeec0>)
sys:1: RuntimeWarning: coroutine 'curio_method' was never awaited
Instead of asyncio.run, you can use curio.run.
But, if you need to use asyncio.run, you can put your curio.run inside your asyncio.run logic. Anyway, I think that is not the idea.

Problem with *.shutdown* command on discord.py

I am currently looking to fix this code. I am trying to make a .shutdown command, which basically logs out of the bot and takes the bot down. I have made a code, but it seems like it is not working. Here is my code. Help is very appreciated ;p
#client.command()
async def shutdown(ctx, *, reason):
if ctx.message.author.id(581457749724889102):
ctx.send('Bot is shutting down... ;(')
logs_channel = client.get_channel(825005282535014420)
logs_channel.send(f"Bot is being shutdown for: {reason}")
exit()
else:
ctx.send("I'm sorry, only officer grr#6609 can do that."
Thanks early for the help!
edit:
here is my error
Ignoring exception in on_command_error
Traceback (most recent call last):
File "C:\Users\USER\AppData\Local\Programs\Python\Python39-32\lib\site-packages\discord\ext\commands\core.py", line 85, in wrapped
ret = await coro(*args, **kwargs)
File "c:\Users\USER\Desktop\discord bot folder\Nuova cartella\connor.py", line 173, in shutdown
if ctx.message.author.id(581457749724889102):
TypeError: 'int' object is not callable
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\USER\AppData\Local\Programs\Python\Python39-32\lib\site-packages\discord\client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "c:\Users\USER\Desktop\discord bot folder\Nuova cartella\connor.py", line 82, in on_command_error
raise error
File "C:\Users\USER\AppData\Local\Programs\Python\Python39-32\lib\site-packages\discord\ext\commands\bot.py", line 902, in invoke
await ctx.command.invoke(ctx)
File "C:\Users\USER\AppData\Local\Programs\Python\Python39-32\lib\site-packages\discord\ext\commands\core.py", line 864, in invoke
await injected(*ctx.args, **ctx.kwargs)
File "C:\Users\USER\AppData\Local\Programs\Python\Python39-32\lib\site-packages\discord\ext\commands\core.py", line 94, in wrapped
raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: 'int' object is not callable
Please always consider to await your functions. You also have some formation and comprehension errors in the code, maybe take another look at the docs
You can check whether the user executing the command is the owner of the bot. If he is not, there is of course an error message.
Have a look at the following code:
#client.command()
#commands.is_owner() # Checks if the bot owner exectued the command
async def shutdown(ctx):
await ctx.send("Logging out.")
await client.logout() # Logging out
#shutdown.error
async def shutdown_error(ctx, error):
if isinstance(error, commands.NotOwner):
await ctx.send("You are not the owner of the bot.") # Error message
What did we do?
awaited most of the functions.
Built in a check to check if the owner executed the command.
Built in an error handler which will give out a message if a non-owner tries to shutdown the bot.

Error "concurrent.futures._base.CancelledError" on server after connection Client

I can not solve the problem with the error after connecting the client to the server. Here is the server code for Python 3.7.7:
#!/usr/bin/env python3
# WS server example
import asyncio
import websockets
#======================================================================
#Register
#======================================================================
async def Register(websocket):
remote_ip = websocket.remote_address[0] #Get client IP
print ("IP: " + remote_ip)
message="Hi. Your IP: " +remote_ip
await websocket.send(message) #Say client IP
print("==> " + str(message))
#======================================================================
#Handler
#======================================================================
async def Handler(websocket, path):
print("Client connect!")
await Register(websocket)
#try:
async for message in websocket:
print("<== " + str(message))
await websocket.send(message)
print("==> " + str(message))
#except Exception as E:
#print(str(E))
#finally:
#await asyncio.sleep(2)
#======================================================================
#MAIN
#======================================================================
print("Starting!")
start_server = websockets.serve(Handler, "0.0.0.0", 8012)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
After connecting, after 40 seconds from the moment of connection, an error is returned, and it does not matter if the client exchanged data with the server or not.
Error in connection handler
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/websockets/protocol.py", line 827, in transfer_data
message = await self.read_message()
File "/usr/local/lib/python3.7/site-packages/websockets/protocol.py", line 895, in read_message
frame = await self.read_data_frame(max_size=self.max_size)
File "/usr/local/lib/python3.7/site-packages/websockets/protocol.py", line 971, in read_data_frame
frame = await self.read_frame(max_size)
File "/usr/local/lib/python3.7/site-packages/websockets/protocol.py", line 1051, in read_frame
extensions=self.extensions,
File "/usr/local/lib/python3.7/site-packages/websockets/framing.py", line 105, in read
data = await reader(2)
File "/usr/local/lib/python3.7/asyncio/streams.py", line 679, in readexactly
await self._wait_for_data('readexactly')
File "/usr/local/lib/python3.7/asyncio/streams.py", line 473, in _wait_for_data
await self._waiter
concurrent.futures._base.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/websockets/server.py", line 191, in handler
await self.ws_handler(self, path)
File "StartWB3.py", line 26, in Handler
async for message in websocket:
File "/usr/local/lib/python3.7/site-packages/websockets/protocol.py", line 439, in __aiter__
yield await self.recv()
File "/usr/local/lib/python3.7/site-packages/websockets/protocol.py", line 509, in recv
await self.ensure_open()
File "/usr/local/lib/python3.7/site-packages/websockets/protocol.py", line 812, in ensure_open
raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedError: code = 1006 (connection closed abnormally [internal]), no reason
What could be the problem?
Thanks in advance for the answers.
The reason is that the underlying socket has been closed and websockets is trying to cancel the task running Handler(). You can catch the error using a try/except block.
Empirically, it turned out that the problem is not in the WebSocket package for Python, but in C # WebSocket4Net: Why is WebSocket4Net closing the connection with 1011 error code
Started using the WebSocketSharp library and the problem disappeared.

Resources