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

schema: multi-tenancy #1140

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open

schema: multi-tenancy #1140

wants to merge 7 commits into from

Conversation

sadath-12
Copy link
Contributor

@sadath-12 sadath-12 commented Aug 12, 2024

Summary

The pr allows the users to pass schema as tenant in headers if the users wants multi-tenancy into their application .
Also it removes Form() reading from /basic/user and uses request.json() to read from body as pydantic does not reset the pointers and causes stream consumed error

Test Plan

Deployment Plan

Signed-off-by: sadath-12 <[email protected]>
Copy link

netlify bot commented Aug 12, 2024

Deploy Preview for thriving-cassata-78ae72 canceled.

Name Link
🔨 Latest commit f046828
🔍 Latest deploy log https://app.netlify.com/sites/thriving-cassata-78ae72/deploys/66bc5ef6a7e6cf00087f9240

"""
Async database session.
"""
session_manager = get_session_manager()
session_manager = get_session_manager(request)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to my other comment, I would just pass in the schema here. so:

session_manager = get_session_manager(schema=request.headers.get("schema")

Signed-off-by: sadath-12 <[email protected]>
@sadath-12 sadath-12 changed the title schema: multi-tenancy [WIP]schema: multi-tenancy Aug 13, 2024
Signed-off-by: sadath-12 <[email protected]>
Signed-off-by: sadath-12 <[email protected]>
@sadath-12 sadath-12 changed the title [WIP]schema: multi-tenancy schema: multi-tenancy Aug 14, 2024
@sadath-12
Copy link
Contributor Author

I have updated the implementation to only route to different schema and remove creation of schema code as discussed with @samredai

Signed-off-by: sadath-12 <[email protected]>
if schema:
engine = engine.execution_options(schema_translate_map={None: schema})

settings.customSchema = request.headers.get("new_tenant")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sadath-12 can you help me understand why you need to modify the settings instance directly like this? Also, since you're pulling schema from the "tenant" header, you don't need this settings property at all anymore, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @samredai , this is to tell dj to switch to the schema when we hit register schema endpoint (created internally) so dj can run migrations on it on runtime or else it will have to be restarted

Copy link
Contributor

@samredai samredai Aug 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sadath-12 I understand the intent here now. I don't think modifying the application settings is the right approach though. Instead we should parameterize the alembic migration scripts (I think I recall @shangyian proposing this). Then in your custom endpoint logic, you can programmatically set that schema parameter using the context.

@ockhamlabs
Copy link

Wondering if this is close to finalization? Anything we can do to help ?

@samredai samredai mentioned this pull request Sep 11, 2024
3 tasks
@samredai
Copy link
Contributor

@ockhamlabs sorry for the late reply here. Let's revisit this after this refactor for the query service goes in which should make this ultimately much easier to achieve. I'm planning to catch up with @sadath-12 soon, either during the community meeting or async.

@sadath-12
Copy link
Contributor Author

(after talk with @samredai )
Note: Whenever we switch across schemas make sure u use existing connection pool

@samredai
Copy link
Contributor

@sadath-12 super sorry for losing track of this. I think we're close to figuring this out--this PR is doing the right thing by parsing the tenant value from the request header, but let's save any of the changes in the datajunction-query directory or to the alembic/env.py file for a follow up PR. If you could update this PR to just include the changes to datajunction_server/config.py and datajunction_server/utils.py, we can iterate on that and get this PR merged pretty quickly.

"""
Get session manager
"""
session_manager = DatabaseSessionManager()
session_manager.schema = request.headers.get("tenant")
settings = get_settings()
settings.customSchema = request.headers.get("new_tenant")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sadath-12 from our discussions I remember you telling me that you had to do this so that the alembic script would run properly when you init a new tenant's schema, but since this commit the alembic scripts are now configurable to target a specific schema. This means in any of your custom endpoints you could do something like this:

from alembic.config import Config
from alembic import command

...
SCHEMA = request.headers.get("tenant") # For example, "tenant1"
if SCHEMA:
    alembic_cfg = Config()
    alembic_cfg.set_main_option("script_location", "./alembic")
    alembic_cfg.cmd_opts = {"x": [f"uri=postgresql+psycopg://username:password@server:5432/{SCHEMA}"]}
    command.upgrade(alembic_cfg, "head")
...

Which means you don't need to add this customSchema to the settings class at all.

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

Successfully merging this pull request may close these issues.

4 participants