Skip to content

AsyncRealtimeChannel.subscribe returns without waiting for an answer #1209

@o-santi

Description

@o-santi

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

When subscribe is called, the channel object will send the payload through the websocket connection and instantly return, without waiting for an answer on whether subscribe was successful or not. This creates some unexpected behavior, as callback is not guaranteed to be called after await channel.subscribe(callback) returns which create non trivial race conditions.

Because of this, even if the callback crashes the program in the case of failure to subscribe to a channel, API calls after subscribe returns are not guarantee to be in a valid subscribed state, as it may be that callback hasn't been called yet.

To Reproduce

Create a supabase start local instance, then run the example given in the README.md:

# test.py
import asyncio
from typing import Optional

from realtime import AsyncRealtimeClient, RealtimeSubscribeStates

async def main():
    REALTIME_URL = "ws://localhost:54321/realtime/v1"
    API_KEY = "{API_KEY}" # api key here

    socket = AsyncRealtimeClient(REALTIME_URL, API_KEY)
    channel = socket.channel("test-channel")
    
    def _on_subscribe(status: RealtimeSubscribeStates, err: Optional[Exception]):
        raise SystemExit(100)

    await channel.subscribe(_on_subscribe)

if __name__ == '__main__':
    asyncio.run(main())
    print('`main()` ran successfully')

Which results in:

$ python test.py
`main()` ran successfully

Even though the callback should've crashed the program instantly.

Expected behavior

After channel.subscribe(callback) is awaited, it should ensure that callback is called by waiting for the answer inside the subscribe async function. Currently, the only way to ensure that it is called is to manually block after the await point with some asyncio.sleep calls, which is not only ugly but also requires you to emulate timeouts externally, even though subscribe does seem to have an internal timeout mechanic.

System information

  • OS: NixOS
  • Version of supabase-py: 2.5.2

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions