Update seat type for seat assignment on member new event
What does this MR do and why?
This code change improves how GitLab tracks and manages user seat assignments for billing purposes.
- Better error handling: When the system can't calculate seat types, it now returns an empty result instead of nothing, preventing potential crashes.
- More accurate seat tracking: The system now calculates and stores the specific type of seat each user occupies (like "base" or "free") based on their access level, rather than just tracking whether they have a seat.
- Smarter updates: Instead of only creating new seat records, the system can now update existing ones when a user's access level changes, ensuring billing accuracy when permissions are modified.
- Performance optimization: The code now caches frequently-used values like namespace and organization IDs to avoid repeated database lookups.
- Enhanced testing: Tests were expanded to verify the new seat type tracking and update functionality works correctly.
This merge request should only be merged after the base merge request !201292 (merged)
Database
Query
GitlabSubscriptions::SeatAssignment.upsert_all(seat_assignments, unique_by: [:namespace_id, :user_id])
SQL
INSERT INTO "subscription_seat_assignments" ("namespace_id","organization_id","user_id","seat_type","created_at","updated_at") VALUES (1, 1, 1, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) ON CONFLICT ("namespace_id","user_id") WHERE (namespace_id IS NOT NULL) DO UPDATE SET updated_at=(CASE WHEN ("subscription_seat_assignments"."organization_id" IS NOT DISTINCT FROM excluded."organization_id" AND "subscription_seat_assignments"."seat_type" IS NOT DISTINCT FROM excluded."seat_type") THEN "subscription_seat_assignments".updated_at ELSE CURRENT_TIMESTAMP END),"organization_id"=excluded."organization_id","seat_type"=excluded."seat_type" RETURNING "id"
Query Plan
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/42609/commands/130346
References
Solves https://gitlab.com/gitlab-org/gitlab/-/issues/552136
Screenshots or screen recordings
| Before | After |
|---|---|
How to set up and validate locally
Start your SaaS GitLab instance locally
- Create a parent group with Ultimate and add two child groups.
- Add a user to one child group with the role
Guest - Check the last
GitlabSubscriptions::SeatAssignment.lastfor the seat typefree - Add the user to the other child group with the role
Developer - Ensure the same seat assignment got updated and the seat type changed to
base
Extended testing
- Create another parent group with Ultimate
- Add the same user to the new group as
guest - See how a new seat assignment with the seat type
guestgets created, and the old one does not get updated- Check with
GitlabSubscriptions::SeatAssignment.last(2)
- Check with
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Edited by Lukas Wanko