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

pn.cache not working with async code: RuntimeError: cannot reuse already awaited coroutine #4236

Closed
MarcSkovMadsen opened this issue Dec 24, 2022 · 3 comments · Fixed by #5649
Labels
type: bug Something isn't correct or isn't working

Comments

@MarcSkovMadsen
Copy link
Collaborator

I'm trying to contribute a guide on Panel+Dask in #4234.

I assume its best to use Dask asynchronously, because then you can off load computation to the dask cluster while still keeping your application responsive.

Then I need a way to instantiate and share the async Dask client that work both in a notebook when people are experimenting and on the server. I assume its best to instantiate the client once and then share it across sessions.

In the notebook you can just do client = await Client(asynchronously) in a cell. But in a script running on the server you cannot use await outside of a function. If I do I get I get an error saying this is not possible.

So instead I think I can just use pn.cache to instantiate once and then share. But this does not work.

import param

from dask.distributed import Client

import panel as pn

pn.extension()

@pn.cache
async def get_client():
    return await Client(asynchronous=True)

submit_button = pn.widgets.Button(name="Submit").servable()

@pn.depends(submit_button, watch=True)
async def run(_):
    print("submit")
    client = await get_client()
panel serve script.py

The second time you click the Submit button you get

$ panel serve script.py
2022-12-24 05:59:38,361 Starting Bokeh server version 2.4.3 (running on Tornado 6.1)
2022-12-24 05:59:38,362 User authentication hooks NOT provided (default user enabled)
2022-12-24 05:59:38,366 Bokeh app running at: http://localhost:5006/script
2022-12-24 05:59:38,366 Starting Bokeh server with process id: 2564
submit
submit
2022-12-24 05:59:47,087 - tornado.application - ERROR - Exception in callback functools.partial(<bound method IOLoop._discard_future_result of <tornado.platform.asyncio.AsyncIOMainLoop object at 0x7f5e6f6b0070>>, <Task finished name='Task-1415' coro=<async_execute.<locals>.wrapper() done, defined at /opt/conda/lib/python3.10/site-packages/panel/io/server.py:155> exception=RuntimeError('cannot reuse already awaited coroutine')>)
Traceback (most recent call last):
  File "/opt/conda/lib/python3.10/site-packages/tornado/ioloop.py", line 741, in _run_callback
    ret = callback()
  File "/opt/conda/lib/python3.10/site-packages/tornado/ioloop.py", line 765, in _discard_future_result
    future.result()
  File "/opt/conda/lib/python3.10/site-packages/panel/io/server.py", line 161, in wrapper
    state._handle_exception(e)
  File "/opt/conda/lib/python3.10/site-packages/panel/io/state.py", line 408, in _handle_exception
    raise exception
  File "/opt/conda/lib/python3.10/site-packages/panel/io/server.py", line 159, in wrapper
    return await func(*args, **kw)
  File "/opt/conda/lib/python3.10/site-packages/param/_async.py", line 28, in cb
    yield from func(*args, **dep_kwargs) # noqa: E999
  File "/home/jovyan/repos/private/panel/script.py", line 18, in run
    client = await get_client()
RuntimeError: cannot reuse already awaited coroutine

Please make pn.cache work with async too or provide a seperate pn.async_cache function.

@MarcSkovMadsen MarcSkovMadsen added the type: bug Something isn't correct or isn't working label Dec 24, 2022
@MarcSkovMadsen
Copy link
Collaborator Author

MarcSkovMadsen commented Dec 24, 2022

Workaround

Instead of using @pn.cache I can use pn.state.cache directly.

async def get_client():
    if not "dask-client" in pn.state.cache:
        pn.state.cache["dask-client"]=await Client(asynchronous=True)
    return pn.state.cache["dask-client"]

@MarcSkovMadsen
Copy link
Collaborator Author

MarcSkovMadsen commented Oct 13, 2023

Just experienced this again when working on panel-chat-examples and trying to make llama_and_mistral.py example more efficient.

@philippjfr
Copy link
Member

The cache presumably should cache the awaitable but the return value of the awaitable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug Something isn't correct or isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants