Skip to content

Add start a trial option in top right user dropdown

What does this MR do?

Adds a Start a trial button with a rocket emoji to the user menu

  • Should only add it to eligible users
  • Rocket emoji 🚀 is used,
  • Only for gitlab.com
  • Code should not go to FOSS edition at this moment

Issue #35637 (closed)

Screenshots

screenshot-2019-11-06-12-51-47

Performance

This will be included on every page view so performance must be ensured:

  • SQL call for any_namespace_without_trial? especially on gitlab.com takes (46.951 ms) at this moment

  • We may omit this call if 46ms is too much for ~10 millions of page views per month.

  • In trials_allowed?(user) proper computation order from cheaper to more expensive

   def trials_allowed?(user)
      ::Gitlab.com? && ::Feature.enabled?(:improved_trial_signup) && user&.any_namespace_without_trial?
    end

SQL EXPLAIN for a user

explain SELECT  1 AS one FROM ((SELECT "namespaces"."trial_ends_on" FROM "namespaces" WHERE "namespaces"."type" IS NULL AND "namespaces"."owner_id" = MY_USER_ID) UNION (SELECT "namespaces"."trial_ends_on" FROM "namespaces" INNER JOIN "members" ON "namespaces"."id" = "members"."source_id" WHERE "members"."type" IN ('GroupMember') AND "members"."source_type" = 'Namespace' AND "namespaces"."type" IN ('Group') AND "members"."user_id" = MY_USER_ID AND "members"."requested_at" IS NULL AND "members"."access_level" = 50 AND "namespaces"."parent_id" IS NULL)) namespaces WHERE "namespaces"."trial_ends_on" IS NULL LIMIT 1```

Full execution time

 Limit  (cost=31.07..31.08 rows=1 width=4) (actual time=44.222..44.227 rows=1 loops=1)
   Buffers: shared dirtied=3 hit=3 read=19
   ->  Subquery Scan  (cost=31.07..31.10 rows=2 width=4) (actual time=44.220..44.220 rows=1 loops=1)
         Buffers: shared dirtied=3 hit=3 read=19
         ->  Unique  (cost=31.07..31.08 rows=2 width=8) (actual time=44.218..44.218 rows=1 loops=1)
               Buffers: shared dirtied=3 hit=3 read=19
               ->  Sort  (cost=31.07..31.07 rows=2 width=8) (actual time=44.217..44.217 rows=1 loops=1)
                     Sort Key: namespaces_1.trial_ends_on
                     Sort Method: quicksort  Memory: 25kB
                     Buffers: shared dirtied=3 hit=3 read=19
                     ->  Append  (cost=0.43..31.06 rows=2 width=8) (actual time=6.829..44.188 rows=1 loops=1)
                           Buffers: shared dirtied=3 read=19
                           ->  Index Scan using index_namespaces_on_owner_id on public.namespaces namespaces_1  (cost=0.43..4.45 rows=1 width=8) (actual time=6.828..6.830 rows=1 loops=1)
                                 Index Cond: (namespaces_1.owner_id = 4409816)
                                 Filter: ((namespaces_1.type IS NULL) AND (namespaces_1.trial_ends_on IS NULL))
                                 Rows Removed by Filter: 0
                                 Buffers: shared read=4
                           ->  Nested Loop  (cost=0.87..26.59 rows=1 width=8) (actual time=37.356..37.356 rows=0 loops=1)
                                 Buffers: shared dirtied=3 read=15
                                 ->  Index Scan using index_members_on_user_id on public.members  (cost=0.43..22.13 rows=1 width=4) (actual time=37.354..37.354 rows=0 loops=1)
                                       Index Cond: (members.user_id = 4409816)
                                       Filter: ((members.requested_at IS NULL) AND ((members.type)::text = 'GroupMember'::text) AND ((members.source_type)::text = 'Namespace'::text) AND (members.access_level = 50))
                                       Rows Removed by Filter: 12
                                       Buffers: shared dirtied=3 read=15
                                 ->  Index Scan using namespaces_pkey on public.namespaces namespaces_2  (cost=0.43..4.45 rows=1 width=12) (actual time=0.000..0.000 rows=0 loops=0)
                                       Index Cond: (namespaces_2.id = members.source_id)
                                       Filter: ((namespaces_2.parent_id IS NULL) AND (namespaces_2.trial_ends_on IS NULL) AND ((namespaces_2.type)::text = 'Group'::text))
                                       Rows Removed by Filter: 0

Times

Cost: 31.10

Time: 46.951 ms
  - planning: 2.625 ms
  - execution: 44.326 ms
    - I/O read: 43.899 ms

Shared buffers:
  - hits: 3 (~24.00 KiB) from the buffer pool
  - reads: 19 (~152.00 KiB) from the OS file cache, including disk I/O
  - dirtied: 3 (~24.00 KiB)
  - writes: 0

Does this MR meet the acceptance criteria?

Conformity

Availability and Testing

Security

If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:

  • Label as security and @ mention @gitlab-com/gl-security/appsec
  • The MR includes necessary changes to maintain consistency between UI, API, email, or other methods
  • Security reports checked/validated by a reviewer from the AppSec team

Closes #35637 (closed)

Edited by Sam Awezec

Merge request reports