question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Executor cannot handle asyncio.sleep() in coroutine

See original GitHub issue

Bug report

Required Info:

  • Operating System:
    • Ubuntu 16.04 and Ubuntu 18.04
  • Installation type:
    • source
  • Version or commit hash:
    • be4bc88
  • DDS implementation:
    • Fast-RTPS
  • Client library (if applicable):
    • rclpy

Steps to reproduce issue

With a ROS 2 workspace built and sourced:

  1. Create foo_service.py with the following content:
import asyncio

from example_interfaces.srv import AddTwoInts

import rclpy


async def add_two_ints_callback(request, response):
    response.sum = request.a + request.b

    await asyncio.sleep(1)

    print('Service request handled')

    return response


def main():
    rclpy.init()
    node = rclpy.create_node('foo_service')
    srv = node.create_service(AddTwoInts, 'add_two_ints', add_two_ints_callback)
    rclpy.spin(node)
    rclpy.shutdown()


if __name__ == '__main__':
    main()
  1. Run the service:

     python3 foo_service.py
    
  2. Run a service client:

     ros2 run examples_rclpy_minimal_client client
    

Expected behavior

Service call succeeds without error.

Actual behavior

Service server crashes from assertion error:

AssertionError: yield from wasn't used with future

Trace:

Traceback (most recent call last):
  File "service.py", line 27, in <module>
    main()
  File "service.py", line 22, in main
    rclpy.spin(node)
  File "/home/jacob/ws/actions_ws/install/rclpy/lib/python3.5/site-packages/rclpy/__init__.py", line 119, in spin
    executor.spin_once()
  File "/home/jacob/ws/actions_ws/install/rclpy/lib/python3.5/site-packages/rclpy/executors.py", line 573, in spin_once
    raise handler.exception()
  File "/home/jacob/ws/actions_ws/install/rclpy/lib/python3.5/site-packages/rclpy/task.py", line 207, in __call__
    self._handler.send(None)
  File "/home/jacob/ws/actions_ws/install/rclpy/lib/python3.5/site-packages/rclpy/executors.py", line 324, in handler
    await call_coroutine(entity, arg)
  File "/home/jacob/ws/actions_ws/install/rclpy/lib/python3.5/site-packages/rclpy/executors.py", line 282, in _execute_service
    response = await await_or_execute(srv.callback, request, srv.srv_type.Response())
  File "/home/jacob/ws/actions_ws/install/rclpy/lib/python3.5/site-packages/rclpy/executors.py", line 89, in await_or_execute
    return await callback(*args)
  File "service.py", line 11, in add_two_ints_callback
    await asyncio.sleep(1)
  File "/usr/lib/python3.5/asyncio/tasks.py", line 516, in sleep
    return (yield from future)
  File "/usr/lib/python3.5/asyncio/futures.py", line 362, in __iter__
    assert self.done(), "yield from wasn't used with future"
AssertionError: yield from wasn't used with future

Additional information

The error appears related to the call to asyncio.sleep(1) in the service server callback. If we replace it with time.sleep(1), the code executes without error.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:3
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
TheDeluscommented, May 21, 2021

Are there plans to support pythons async and await syntax in the future? Not beeing able to use pythons own system of coroutines and async execution is one of a the big things holding us back migrating to ROS2. With ROS1 we use the workaround provided by locusrobotics/aiorospy.

Sorry for hijacking this is issue, but it appears to be the most fitting place for my question.

2reactions
sloretzcommented, Mar 14, 2019

I’m not well-versed with the decision to define our own Future and Task classes, but perhaps it’s possible to replace them with equivalents in asyncio.

There are two standard modules for executors/tasks/futures: concurrent.futures which is thread safe but does not support coroutines, and asyncio which supports coroutines but is not threadsafe. The rclpy executor supports both multiple threads and coroutines, so it has to have its own 😦

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why coroutines cannot be used with run_in_executor?
You have to create and set a new event loop in the thread context in order to run coroutines: import asyncio from concurrent.futures...
Read more >
Event Loop — Python 3.11.1 documentation
After calling this method, a RuntimeError will be raised if loop.run_in_executor() is called while using the default executor. Note that there is no...
Read more >
How to Get the Asyncio Coroutine from a Task in Python
You can get the coroutine wrapped in a task by calling the get_coro() method on the Task object. In this tutorial, you will...
Read more >
Source code for asgiref.sync - Django documentation
import asyncio.coroutines import contextvars import functools import inspect ... so that tasks can work out what their parent used. executors = Local() def ......
Read more >
Coroutines (C++20) - cppreference.com
This is a non-owning handle used to resume execution of the coroutine or to destroy the coroutine frame. the coroutine state, which is...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found