-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
feat: Migrate organizations list to control #92442
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
base: master
Are you sure you want to change the base?
Conversation
order_by = "-date_added" | ||
paginator_cls = DateTimePaginator | ||
|
||
# return paginate( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this would need migrated, shoudl be easy enough
show: Show | None = None, | ||
sort_by: SortBy | None = "date", | ||
# actor specific stuff | ||
actor_user_id: int, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
preferably this is a similar construct to 'request.auth' but something all RPC endpoints gain access to - "the current actor"
ALL = "all" | ||
|
||
|
||
def list_organizations( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
broken out into its own module just because the giant impl file is insanity
order_by = "-member_count" | ||
paginator_cls = OffsetPaginator | ||
elif sort_by == "projects": | ||
queryset = queryset.annotate(project_count=Count("project")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
confirm: are projects on control? i think they should be
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Projects are not available in Control Silo:
sentry/src/sentry/models/project.py
Line 228 in 59c3578
class Project(Model): |
Similarly, organizations are not fully available in Control Silo either:
sentry/src/sentry/models/organization.py
Line 144 in 59bd9f3
class Organization(ReplicatedRegionModel): |
We do have a thin replicated version of organizations in Control though (OrganizationMapping)
I don't have the full context on that particular decision, though @markstory could probably weigh in on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Projects are not available in Control Silo:
Projects are organization scoped, and needed to stay in the region for existing transactions and application logic to work. Because all of this logic will need to be region scoped (because of organization) you'll also be able to use projects.
ALL = "all" | ||
|
||
|
||
def list_organizations( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the API would call this RPC method, and if its fails remotely (e.g. on control), could try/catch onto calling local?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the API would call this RPC method, and if its fails remotely (e.g. on control), could try/catch onto calling local?
That isn't typically how RPC services work. Instead they choose a mode (rpc proxy or local) based on the silo mode that the application is deployed in.
❌ 8 Tests Failed:
View the top 3 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
91f08bc
to
9ebb327
Compare
9ebb327
to
46392e1
Compare
46392e1
to
b79c998
Compare
@markstory is there a reason I cant make this new method be:
And not even add it to the existing mega class? |
@markstory how do i know if somethings on control vs region? i see both org/project with |
I'm curious what the intention is behind this change, and how the full implementation will look. In particular, these parts:
Is the idea to have a control endpoint fan out to all available regions a user has data in, in order to retrieve the full list of organizations that user belongs to? |
The intention behind this change is to fix what is a broken API experience today. Right now the API no longer works for any metadata endpoint, as you'd have to query every region silo that might possibly exist, which is particularly a problem for core user and organization-style metadata. This exposed itself in the MCP server when users with DE-only orgs received empty responses. My original thinking was:
I might have to revisit that plan. I'm also going to push us to revisit why its structured this way in the first place as it creates a lot of undue complexity, but I'm sure there was a reason. If you designed this from the ground up you'd have the following system:
This is kind of what we have, but clearly not all the way given data appears to almost never? live in the control plane. You'd then design two APIs: a control plane API (e.g. the /organizations endpoint) and the individual tenants APIs (the region silo endpoints). This is generally speaking how you'd want to design any of these tenant based systems, otherwise you have no way to actually identify data without magic knowledge in a system (e.g. I "know" there is DE and US tenants). We are half way there. Organization responses give you their regionUrl. The problem is those responses cannot be achieved without.. regional responses. I think the tl;dr is organization needs migrated to control, just like user is. |
Got it. I think it makes sense to revisit this decision, since this has caused a fair bit of friction in some of our other APIs (organization/subscription provisioning are the most obvious two I can think of). I do want to call out that this may be a considerable amount of work to actually achieve. In the meantime, we do support a control-silo endpoint that supplies all available region URLs a user has data in via the |
ALL = "all" | ||
|
||
|
||
def list_organizations( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the API would call this RPC method, and if its fails remotely (e.g. on control), could try/catch onto calling local?
That isn't typically how RPC services work. Instead they choose a mode (rpc proxy or local) based on the silo mode that the application is deployed in.
order_by = "-member_count" | ||
paginator_cls = OffsetPaginator | ||
elif sort_by == "projects": | ||
queryset = queryset.annotate(project_count=Count("project")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Projects are not available in Control Silo:
Projects are organization scoped, and needed to stay in the region for existing transactions and application logic to work. Because all of this logic will need to be region scoped (because of organization) you'll also be able to use projects.
{"organization": serialize(org), "singleOwner": org.has_single_owner()} | ||
) | ||
|
||
return Response(org_results) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this will work as RPC services need to serialize their return values into JSON via pydantic models.
order_by=order_by, | ||
on_results=lambda x: serialize(x, request.user), | ||
paginator_cls=paginator_cls, | ||
result = organization_service.list_organizations( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another wrinkle we'll run into with having org list be available on control is that we don't have a way for an endpoint to be partially in control and partially in region. The other methods on this endpoint need to stay in the region because they mutate the organization. Django might not like having two endpoints bound to the same URL as well.
Quick update here - I chatted more with Mark on this. I'm not totally sure what the right direction is right now. I think the outcome is clear to me: things like /organizations should just list all orgs you're a member of - no matter the region. I have temporarily worked around this in the MCP, but all versions of fixing this in Sentry are a little complex. I think it MUST get fixed, but I also have a hard time saying it MUST get fixed tomorrow. IMO the best course of action while this is in conversation: what do we want this to function like, write that down, then we work towards it when time permits. |
WIP
Here's the planned changes: