Exclude add-on purchases from active that are expiring today
What does this MR do and why?
Part of https://gitlab.com/gitlab-org/gitlab/-/issues/465546+
Prior to this change, an add-on purchase was considered still active if it was expiring today. This doesn't align with how subscriptions are handled on the CustomersDot side where the end date is excluded from the current term.
This change aligns the end date check for active add-on purchases to exclude the end date. Additionally, it now checks the start date as well. Any add-on purchases without a start date will be considered active as long as the expires on date is less than today.
MR acceptance checklist
Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Database queries
GitlabSubscriptions::AddOnPurchase.active
scope
Raw SQL for before:
SELECT
subscription_add_on_purchases.*
FROM
subscription_add_on_purchases
WHERE
expires_on >= '2024-09-02';
after:
SELECT
subscription_add_on_purchases.*
FROM
subscription_add_on_purchases
WHERE
(
started_at IS NULL OR
started_at <= '2024-09-02'
) AND
'2024-09-02' < expires_on;
Query plans
- Query plans for only
.active
scope: https://console.postgres.ai/gitlab/gitlab-production-main/sessions/31178/commands/96834 - Without a namespace: https://console.postgres.ai/gitlab/gitlab-production-main/sessions/31150/commands/96745
- With namespace set to
NULL
: https://console.postgres.ai/gitlab/gitlab-production-main/sessions/31150/commands/96746 - With namespace set to
9970
(gitlab-org
): https://console.postgres.ai/gitlab/gitlab-production-main/sessions/31150/commands/96749
Database migrations
Up migrations
main: == [advisory_lock_connection] object_id: 128260, pg_backend_pid: 49935
main: == 20240830105808 AddIndexToSubscriptionAddOnPurchasesStartedAtAndExpiresOn: migrating
main: -- transaction_open?(nil)
main: -> 0.0000s
main: -- view_exists?(:postgres_partitions)
main: -> 0.0141s
main: -- index_exists?(:subscription_add_on_purchases, [:started_at, :expires_on], {:name=>"idx_subscription_add_on_purchases_on_started_on_and_expires_on", :algorithm=>:concurrently})
main: -> 0.0033s
main: -- execute("SET statement_timeout TO 0")
main: -> 0.0003s
main: -- add_index(:subscription_add_on_purchases, [:started_at, :expires_on], {:name=>"idx_subscription_add_on_purchases_on_started_on_and_expires_on", :algorithm=>:concurrently})
main: -> 0.0025s
main: -- execute("RESET statement_timeout")
main: -> 0.0004s
main: == 20240830105808 AddIndexToSubscriptionAddOnPurchasesStartedAtAndExpiresOn: migrated (0.0362s)
main: == [advisory_lock_connection] object_id: 128260, pg_backend_pid: 49935
ci: == [advisory_lock_connection] object_id: 128520, pg_backend_pid: 49937
ci: == 20240830105808 AddIndexToSubscriptionAddOnPurchasesStartedAtAndExpiresOn: migrating
ci: -- transaction_open?(nil)
ci: -> 0.0000s
ci: -- view_exists?(:postgres_partitions)
ci: -> 0.0006s
ci: -- index_exists?(:subscription_add_on_purchases, [:started_at, :expires_on], {:name=>"idx_subscription_add_on_purchases_on_started_on_and_expires_on", :algorithm=>:concurrently})
ci: -> 0.0030s
ci: -- execute("SET statement_timeout TO 0")
ci: -> 0.0036s
ci: -- add_index(:subscription_add_on_purchases, [:started_at, :expires_on], {:name=>"idx_subscription_add_on_purchases_on_started_on_and_expires_on", :algorithm=>:concurrently})
ci: -> 0.0017s
ci: -- execute("RESET statement_timeout")
ci: -> 0.0003s
ci: == 20240830105808 AddIndexToSubscriptionAddOnPurchasesStartedAtAndExpiresOn: migrated (0.0224s)
ci: == [advisory_lock_connection] object_id: 128520, pg_backend_pid: 49937
Down migrations
main: == [advisory_lock_connection] object_id: 127800, pg_backend_pid: 47621
main: == 20240830105808 AddIndexToSubscriptionAddOnPurchasesStartedAtAndExpiresOn: reverting
main: -- transaction_open?(nil)
main: -> 0.0000s
main: -- view_exists?(:postgres_partitions)
main: -> 0.0123s
main: -- index_exists?(:subscription_add_on_purchases, [:started_at, :expires_on], {:name=>"idx_subscription_add_on_purchases_on_started_on_and_expires_on", :algorithm=>:concurrently})
main: -> 0.0028s
main: -- execute("SET statement_timeout TO 0")
main: -> 0.0003s
main: -- remove_index(:subscription_add_on_purchases, {:name=>"idx_subscription_add_on_purchases_on_started_on_and_expires_on", :algorithm=>:concurrently, :column=>[:started_at, :expires_on]})
main: -> 0.0033s
main: -- execute("RESET statement_timeout")
main: -> 0.0003s
main: == 20240830105808 AddIndexToSubscriptionAddOnPurchasesStartedAtAndExpiresOn: reverted (0.0333s)
main: == [advisory_lock_connection] object_id: 127800, pg_backend_pid: 47621
ci: == [advisory_lock_connection] object_id: 127800, pg_backend_pid: 48210
ci: == 20240830105808 AddIndexToSubscriptionAddOnPurchasesStartedAtAndExpiresOn: reverting
ci: -- transaction_open?(nil)
ci: -> 0.0000s
ci: -- view_exists?(:postgres_partitions)
ci: -> 0.0132s
ci: -- index_exists?(:subscription_add_on_purchases, [:started_at, :expires_on], {:name=>"idx_subscription_add_on_purchases_on_started_on_and_expires_on", :algorithm=>:concurrently})
ci: -> 0.0035s
ci: -- execute("SET statement_timeout TO 0")
ci: -> 0.0004s
ci: -- remove_index(:subscription_add_on_purchases, {:name=>"idx_subscription_add_on_purchases_on_started_on_and_expires_on", :algorithm=>:concurrently, :column=>[:started_at, :expires_on]})
ci: -> 0.0034s
ci: -- execute("RESET statement_timeout")
ci: -> 0.0004s
ci: == 20240830105808 AddIndexToSubscriptionAddOnPurchasesStartedAtAndExpiresOn: reverted (0.0408s)
ci: == [advisory_lock_connection] object_id: 127800, pg_backend_pid: 48210
How to set up and validate locally
- Start a new rails console in sandbox mode:
bin/rails c --sandbox
- Create a couple of
GitlabSubscriptions::AddOnPurchase
with different dates forstarted_at
andexpires_on
to verify theGitlabSubscriptions::AddOnPurchase.active
is working as expected.
Edited by Bishwa Hang Rai