You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When using spin_until_future_complete with a task that await on a future set in a timer, the future is never completed. Interestingly, this only happens when setting a timeout on spin_until_future_complete, if a timeout is not provided, or if None is provided, then the task completes successfully.
Required Info:
Operating System:
ubuntu22.04
Installation type:
Binary
Version or commit hash:
3.3.4-1jammy.20220620.181239
DDS implementation:
default
Client library (if applicable):
rclpy
Steps to reproduce issue
importrclpyimportrclpy.nodeimportrclpy.executorsrclpy.init()
node=rclpy.node.Node("test_node")
executor=rclpy.executors.SingleThreadedExecutor()
executor.add_node(node)
fut=rclpy.Future()
asyncdefwork():
node.create_timer(0.1, lambda: fut.set_result(True))
awaitfuttask=executor.create_task(work())
executor.spin_until_future_complete(task, 1) # works when timeout is Noneprint(task.done())
rclpy.shutdown()
Expected behavior
Future is completed
Actual behavior
Future is not completed
Additional information
Looking at the code of spin_until_future_complete, it behaves differently depending on if a timeout is provided.
This all looks good but furthur investigation of wait_for_ready_callbacks (which is eventually called later down the chain),
whileTrue:
ifself._cb_iterisNoneorself._last_args!=argsorself._last_kwargs!=kwargs:
# Create a new generatorself._last_args=argsself._last_kwargs=kwargsself._cb_iter=self._wait_for_ready_callbacks(*args, **kwargs)
try:
returnnext(self._cb_iter)
exceptStopIteration:
# Generator ran out of workself._cb_iter=None
It creates a new generator whenever _last_args or _last_kwargs is different, the "timeout" path of spin_until_future_complete does exactly that, each spin_once_until_future_complete is passed a different timeout.
My guess is that somehow creating new generators every "tick" causes new "work" to be created, and executing a "work" causes a new generator to be created, resulting in a infinite list of pending "work", which causes the actual task to never be executed.
I also notice that when adding a print statement to Future.__await__(), the same future is being yielded endlessly very quickly.
def__await__(self):
# Yield if the task is not finishedwhilenotself._done:
print(id(self), "yielding")
yieldreturnself.result()
Bug report
When using
spin_until_future_complete
with a task thatawait
on a future set in a timer, the future is never completed. Interestingly, this only happens when setting a timeout onspin_until_future_complete
, if a timeout is not provided, or ifNone
is provided, then the task completes successfully.Required Info:
Steps to reproduce issue
Expected behavior
Future is completed
Actual behavior
Future is not completed
Additional information
Looking at the code of
spin_until_future_complete
, it behaves differently depending on if a timeout is provided.This all looks good but furthur investigation of
wait_for_ready_callbacks
(which is eventually called later down the chain),It creates a new generator whenever
_last_args
or_last_kwargs
is different, the "timeout" path ofspin_until_future_complete
does exactly that, eachspin_once_until_future_complete
is passed a different timeout.My guess is that somehow creating new generators every "tick" causes new "work" to be created, and executing a "work" causes a new generator to be created, resulting in a infinite list of pending "work", which causes the actual task to never be executed.
I also notice that when adding a
print
statement toFuture.__await__()
, the same future is being yielded endlessly very quickly.output
The text was updated successfully, but these errors were encountered: