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

Supabase Python Client does not close connection & hangs #494

Closed
djmango opened this issue Jul 18, 2023 · 15 comments
Closed

Supabase Python Client does not close connection & hangs #494

djmango opened this issue Jul 18, 2023 · 15 comments

Comments

@djmango
Copy link

djmango commented Jul 18, 2023

Describe the bug
The Supabase Python client does not close its connection when it goes out of scope or is deleted, leading to connections persisting after tests are completed in a Django test suite.

To Reproduce
Here's an example of code that reproduces the behavior:

class JWTTest(TestCase):
    def setUp(self):
        self.supabase: SupabaseClient = create_client(os.environ['SUPABASE_URL'], os.environ['SUPABASE_KEY'])

    def tearDown(self):
        pass

    def test_jwt(self):
        # test code...

Steps to reproduce the behavior:

  1. Set up a Django test case that uses the Supabase Python client.
  2. Run a test method that uses the Supabase client.
  3. After the test is completed, the connection to Supabase does not close, preventing Django from cleaning up the test database.

Expected behavior
The Supabase Python client should automatically close its connection when it goes out of scope or is deleted, allowing Django to clean up its test database after tests are run.

Desktop (please complete the following information):

  • OS: Mac OS 13.5
  • Python version: 3.11
  • Supabase Python client version: 1.0.3

Additional context
This issue has caused problems in running Django test suites, as it prevents Django from deleting its test database due to the persistent connection. I haven't found any valid workarounds besides keyboard interrupt (e.g., forcing garbage collection), it would be better if the Supabase client could handle this automatically. Additionally, I tested this in a minimal script that just initializes the Supabase client, and the behavior is the same.

@Ben-Epstein
Copy link

+1 I'm experiencing the same thing here

@vidbina
Copy link

vidbina commented Sep 4, 2023

Also stumbled into this issue whenever accessing anything supabase.auth-related (like supabase.auth.sign_up to create a test user).

The workaround I settled for was seeding a test user such that I don't have to call any of the supabase.auth functions for now.

INSERT INTO auth.users
(id, instance_id, aud, role, email, encrypted_password, created_at, updated_at, email_confirmed_at, confirmation_sent_at, raw_app_meta_data)
VALUES
('d2ab3142-6538-4e6e-a43b-52a0ffb3ea93', '00000000-0000-0000-0000-000000000000', 'authenticated', 'authenticated', 'test@example.org', 'ENCRYPTED', now(), now(), now(), now(), '{"provider":"email","providers":["email"]}')
RETURNING *;

My sloppy workaround was adding this to seed for now, but a cleaner setup would be to call this during setup and then removing it during teardown instead. 🙈

@Ben-Epstein
Copy link

Also stumbled into this issue whenever accessing anything supabase.auth-related (like supabase.auth.sign_up to create a test user).

@vidbina Same exact issue for me, supabase.auth was the core problem. I tried that in the seed but it didn't seem to work for me, the user wasn't "confirmed" so I couldn't access them. I ended up doing this, which did work for me, and allowed for the teardown you were looking for

        res = requests.post(signup_url, json={"email": user["email"], "password": user["password"]}, headers=headers)
        # User may already exist. That's OK
        if res.status_code != 200:
            return
        user_id = res.json()["user"]["id"]
        client_ = create_client(SUPABASE_URL, SUPABASE_SECRET)
        client_.table("api_tokens").insert(
            {"user_id": user_id, "token": user["token"], "expiry": "2099-01-01"}
        ).execute()

and then I tear them down with another post request at the end.

@silentworks
Copy link
Contributor

Can one of you provide a reproducible example repo with this issue? It's easier for us to debug the issue if this is provided.

@jkeyes
Copy link

jkeyes commented Oct 7, 2023

@silentworks I don't have an example repo, but I found this ticket after a search as I encountered this problem in a very simple standalone script (also mentioned above by @djmango in the issue description). The user email@example.com exists in the authentication table and after printing the user object the script hangs.

import os
from supabase import create_client

# create client
url = os.environ.get("SUPABASE_TEST_URL")
key = os.environ.get("SUPABASE_TEST_KEY")
client = create_client(url, key)

# sign in
random_email: str = "email@example.com"
random_password: str = "big-secret"
user = client.auth.sign_in_with_password(
    {"email": random_email, "password": random_password}
)
print(user)

After Ctrl-c the following trace is displayed:

Exception ignored in: <module 'threading' from '.../3.9.13/lib/python3.9/threading.py'>
Traceback (most recent call last):
  File ".../3.9.13/lib/python3.9/threading.py", line 1477, in _shutdown
    lock.acquire()
KeyboardInterrupt: 

Hope that helps.

@kmckiern
Copy link

I am experiencing this same issue

@silentworks I don't have an example repo, but I found this ticket after a search as I encountered this problem in a very simple standalone script (also mentioned above by @djmango in the issue description). The user email@example.com exists in the authentication table and after printing the user object the script hangs.

import os
from supabase import create_client

# create client
url = os.environ.get("SUPABASE_TEST_URL")
key = os.environ.get("SUPABASE_TEST_KEY")
client = create_client(url, key)

# sign in
random_email: str = "email@example.com"
random_password: str = "big-secret"
user = client.auth.sign_in_with_password(
    {"email": random_email, "password": random_password}
)
print(user)

After Ctrl-c the following trace is displayed:

Exception ignored in: <module 'threading' from '.../3.9.13/lib/python3.9/threading.py'>
Traceback (most recent call last):
  File ".../3.9.13/lib/python3.9/threading.py", line 1477, in _shutdown
    lock.acquire()
KeyboardInterrupt: 

Hope that helps.

@oofaish
Copy link

oofaish commented Oct 20, 2023

this hangs for me every time

from supabase import create_client
import os

client = create_client(
    os.environ.get("SUPABASE_URL"),
    os.environ.get("SUPBASE_PROJECT_API_KEY"),
)

client.auth.sign_in_with_password(
    {"email": os.environ.get("SUPABASE_USER"), "password": os.environ.get("SUPABASE_PASSWORD")}
)

without the sign_in_with_password it does not hang.

(running supabase v 1.2 - on python 3.11)
(which is exactly the same issue as @jkeyes 🤦🏻‍♂️

@oofaish
Copy link

oofaish commented Oct 20, 2023

FWIW's in my case if I do end my code with
client.auth.sign_out() it doesn't hang any more, but I am not sure that's the behaviour we want? 🤔

@valvesss
Copy link

+1

@valvesss
Copy link

valvesss commented Oct 20, 2023

    # Creates supabase user
    response = self.supabase.auth.sign_up({ "email": user_email, 
                                            "password": user_password })
    
    self.supabase.auth.sign_out()

signing out hangs for me, i dont think thats the expected behavior!

@silentworks
Copy link
Contributor

I have tested this and calling sign_out() fixes the issue for me. The reason it hangs when you don't call sign_out() is because there is a timer thread which is used to refresh the auth token which is only closed when sign_out() is called. You can see a related issue here which was closed #451. I have also included a screen recording of the hanging when sign_out() is not called and no hanging when sign_out() is called.

Kapture.2023-10-24.at.23.32.42.mp4

@silentworks
Copy link
Contributor

Closing this out as there has been no activity since my last reply.

@oofaish
Copy link

oofaish commented Jan 12, 2024

Sorry @silentworks i missed the reply but I would say the client needs to use a daemon thread to make sure it does not hang the whole application.

https://docs.python.org/3/library/threading.html#threading.Thread.daemon

@vikyw89
Copy link

vikyw89 commented Jan 23, 2024

can concur this happened to me to when using it with pytest, and I also use signInWithPassword

@jbasko
Copy link

jbasko commented Apr 1, 2024

For others coming here, the solution is this one:
#451 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants