Skip to content

Background task results are lost #3090

@hoffmanr-cshs

Description

@hoffmanr-cshs

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Tasks created by passing Sanic.add_task a coroutine or callable always have a .result() of None.

This seems to be due to the Sanic._prep_task function, that wraps the passed task and attempts to inject the app as an arg. See: https://github.com/sanic-org/sanic/blame/a64d7fe6edb65ac60537f91d4d6c34fe7bc224b9/sanic/app.py#L1646

This wrapper is invoked for all delayed tasks, as well as in _loop_add_task for any inputs that are not already type(Future) (i.e. coroutines and callables).

I believe this could be fixed by changing the linked line in _prep_task from await task to return await task. In my testing this had the expected result.

Code snippet

async def foo(x)
  await asyncio.sleep(0)
  return x

task = app.create_task(foo(42), name='foo42')
await task  # => None
task.result()  # => None
app.get_task('foo42').result()  # => None

# manually wrapping the coroutine in a Future bypasses _prep_task():
task2 = app.create_task(asyncio.ensure_future(foo(42)), name='foo42-2')
await task2  # => 42
task2.result()  # => 42

Expected Behavior

Given the comparison to asyncio.create_task in the documentation, I would expect tasks scheduled with this convenience function to have their results accessible in the same way - by either await task or task.result().

Though the wrapper can be bypassed (at least in some situations) by first wrapping the task-to-be in asyncio.ensure_future or asyncio.create_task, this behavior is opaque and confusing. If for whatever reason it is an intentional design choice, and there's some part of the code that is relying on awaited tasks always being Nones, I think this should at least be explained in the background tasks documentation, as it's a departure from how asyncio.create_task behaves.

How do you run Sanic?

Sanic CLI

Operating System

Linux

Sanic Version

Sanic 24.12.0 (code appears the same in main)

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions