cal.com icon indicating copy to clipboard operation
cal.com copied to clipboard

chore: platform api usage based billing using queue

Open ThyMinimalDev opened this issue 1 year ago • 8 comments

What does this PR do?

Usage based billing for platform api using Bull Queue

  • Creating a booking
    • a job is created to increment the usage when the booking will start
  • Canceling a booking
    • cancel the job that was supposed to run to increment usage when booking would start
  • Reschedule
    • cancel the job that was supposed to run to increment usage when booking would start
    • create a new job to increment usage when rescheduled booking will happen

if you are wondering why we don't simply tell stripe to decrement usage, it's simply because stripe does not allow it.

ThyMinimalDev avatar May 16 '24 23:05 ThyMinimalDev

Thank you for following the naming conventions! 🙏 Feel free to join our discord and post your PR link.

github-actions[bot] avatar May 16 '24 23:05 github-actions[bot]

Graphite Automations

"Add foundation team as reviewer" took an action on this PR • (05/16/24)

1 reviewer was added to this PR based on Keith Williams's automation.

"Add platform team as reviewer" took an action on this PR • (05/16/24)

1 reviewer was added to this PR based on Keith Williams's automation.

graphite-app[bot] avatar May 16 '24 23:05 graphite-app[bot]

New and removed dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
npm/[email protected] environment 0 31.4 kB streamich

🚮 Removed packages: npm/[email protected], npm/[email protected]

View full report↗︎

socket-security[bot] avatar May 16 '24 23:05 socket-security[bot]

No dependency changes detected. Learn more about Socket for GitHub ↗︎

👍 No dependency changes detected in pull request

socket-security[bot] avatar May 16 '24 23:05 socket-security[bot]

The latest updates on your projects. Learn more about Vercel for Git ↗︎

3 Skipped Deployments
Name Status Preview Comments Updated (UTC)
ai ⬜️ Ignored (Inspect) Visit Preview Jul 24, 2024 2:19pm
cal ⬜️ Ignored (Inspect) Visit Preview Jul 24, 2024 2:19pm
calcom-web-canary ⬜️ Ignored (Inspect) Visit Preview Jul 24, 2024 2:19pm

vercel[bot] avatar May 16 '24 23:05 vercel[bot]

📦 Next.js Bundle Analysis for @calcom/web

This analysis was generated by the Next.js Bundle Analysis action. 🤖

Eighty-five Pages Changed Size

The following pages changed size from the code in this PR compared to its base branch:

Page Size (compressed) First Load % of Budget (350 KB)
/apps 277.5 KB 505.16 KB 144.33% (🟢 -1.91%)
/apps/[slug] 294.88 KB 522.54 KB 149.30% (🟢 -1.97%)
/apps/[slug]/[...pages] 587.32 KB 814.97 KB 232.85% (🟢 -1.52%)
/apps/categories 254.55 KB 482.21 KB 137.77% (🟢 -1.71%)
/apps/categories/[category] 259.36 KB 487.01 KB 139.15% (🟢 -1.99%)
/apps/installation/[[...step]] 467.39 KB 695.05 KB 198.59% (🔴 +85.63%)
/apps/installed/[category] 278.5 KB 506.15 KB 144.61% (🟢 -1.74%)
/auth/saml-idp 12.22 KB 239.88 KB 68.54% (🟢 -20.80%)
/availability 426.9 KB 654.56 KB 187.02% (🟢 -1.58%)
/availability/[schedule] 410.77 KB 638.43 KB 182.41% (🟢 -1.59%)
/booking/[uid] 236.87 KB 464.52 KB 132.72% (🟡 +0.26%)
/booking/[uid]/embed 236.87 KB 464.53 KB 132.72% (🟡 +0.26%)
/bookings/[status] 324.57 KB 552.23 KB 157.78% (🟢 -1.61%)
/enterprise 254.6 KB 482.26 KB 137.79% (🟢 -1.71%)
/event-types 559.92 KB 787.58 KB 225.02% (🟢 -1.55%)
/event-types/[type] 435.69 KB 663.35 KB 189.53% (🟢 -1.67%)
/getting-started/[[...step]] 448.15 KB 675.8 KB 193.09% (🟡 +10.72%)
/insights 474.55 KB 702.2 KB 200.63% (🟢 -1.71%)
/more 254.11 KB 481.77 KB 137.65% (🟢 -1.72%)
/payment/[uid] 121.27 KB 348.93 KB 99.69% (🟡 +0.20%)
/settings/admin 260.58 KB 488.24 KB 139.50% (🟢 -1.69%)
/settings/admin/apps 273.96 KB 501.62 KB 143.32% (🟢 -1.68%)
/settings/admin/apps/[category] 273.95 KB 501.6 KB 143.32% (🟢 -1.68%)
/settings/admin/flags 264.41 KB 492.07 KB 140.59% (🟢 -1.69%)
/settings/admin/impersonation 260.97 KB 488.63 KB 139.61% (🟢 -1.69%)
/settings/admin/lockedSMS 282.07 KB 509.72 KB 145.63% (🟢 -1.66%)
/settings/admin/lockedSMS/lockedSMSView 119.52 KB 347.17 KB 99.19% (🟢 -0.15%)
/settings/admin/oAuth 272.69 KB 500.35 KB 142.96% (🟢 -1.69%)
/settings/admin/oAuth/oAuthView 95.41 KB 323.07 KB 92.30% (🟢 -0.20%)
/settings/admin/orgMigrations/_OrgMigrationLayout 249.36 KB 477.02 KB 136.29% (🟢 -1.73%)
/settings/admin/orgMigrations/moveTeamToOrg 299.28 KB 526.94 KB 150.55% (🟢 -1.66%)
/settings/admin/orgMigrations/moveUserToOrg 319.11 KB 546.77 KB 156.22% (🟢 -1.64%)
/settings/admin/orgMigrations/removeTeamFromOrg 299.05 KB 526.7 KB 150.49% (🟢 -1.67%)
/settings/admin/orgMigrations/removeUserFromOrg 299.06 KB 526.71 KB 150.49% (🟢 -1.66%)
/settings/admin/organizations 262.47 KB 490.12 KB 140.03% (🟢 -1.68%)
/settings/admin/organizations/[id]/edit 261.13 KB 488.78 KB 139.65% (🟢 -1.69%)
/settings/admin/users 263.24 KB 490.89 KB 140.26% (🟢 -1.69%)
/settings/admin/users/[id]/edit 392.44 KB 620.1 KB 177.17% (🟢 -1.65%)
/settings/admin/users/add 392.11 KB 619.77 KB 177.08% (🟢 -1.66%)
/settings/billing 260.79 KB 488.44 KB 139.55% (🟢 -1.68%)
/settings/developer/api-keys 265.18 KB 492.84 KB 140.81% (🟢 -1.69%)
/settings/developer/webhooks 265.36 KB 493.01 KB 140.86% (🟢 -1.69%)
/settings/developer/webhooks/[id] 266.34 KB 493.99 KB 141.14% (🟢 -1.67%)
/settings/developer/webhooks/new 266.36 KB 494.02 KB 141.15% (🟢 -1.67%)
/settings/my-account/appearance 313.8 KB 541.46 KB 154.70% (🟢 -1.68%)
/settings/my-account/calendars 272.21 KB 499.86 KB 142.82% (🟢 -1.73%)
/settings/my-account/conferencing 273.12 KB 500.78 KB 143.08% (🟢 -1.72%)
/settings/my-account/general 376.29 KB 603.95 KB 172.56% (🟢 -1.68%)
/settings/my-account/out-of-office 265.82 KB 493.47 KB 140.99% (🟢 -1.69%)
/settings/my-account/profile 408.81 KB 636.47 KB 181.85% (🟢 -1.66%)
/settings/organizations/[id]/about 159.7 KB 387.36 KB 110.67% (🟡 +0.49%)
/settings/organizations/[id]/add-teams 159.7 KB 387.35 KB 110.67% (🟡 +0.49%)
/settings/organizations/admin-api 260.74 KB 488.39 KB 139.54% (🟢 -1.69%)
/settings/organizations/appearance 122.37 KB 350.03 KB 100.01% (🟢 -48.01%)
/settings/organizations/billing 260.82 KB 488.48 KB 139.57% (🟢 -1.69%)
/settings/organizations/dsync 293.44 KB 521.1 KB 148.89% (🟢 -1.69%)
/settings/organizations/general 349.13 KB 576.79 KB 164.80% (🟢 -1.69%)
/settings/organizations/members 400.3 KB 627.96 KB 179.42% (🟢 -1.68%)
/settings/organizations/new 159.71 KB 387.36 KB 110.68% (🟡 +0.48%)
/settings/organizations/privacy 266.34 KB 493.99 KB 141.14% (🟢 -1.69%)
/settings/organizations/profile 417.35 KB 645 KB 184.29% (🟡 +2.92%)
/settings/organizations/sso 271.41 KB 499.07 KB 142.59% (🟢 -1.69%)
/settings/organizations/teams/other 261.65 KB 489.31 KB 139.80% (🟢 -1.69%)
/settings/organizations/teams/other/[id]/appearance 273.56 KB 501.21 KB 143.20% (🟢 -1.63%)
/settings/organizations/teams/other/[id]/members 268.25 KB 495.91 KB 141.69% (🟢 -1.69%)
/settings/organizations/teams/other/[id]/profile 472.03 KB 699.68 KB 199.91% (🟢 -1.67%)
/settings/platform 259.21 KB 486.87 KB 139.10% (🟢 -1.71%)
/settings/platform/new 120.72 KB 348.37 KB 99.53% (🟡 +0.52%)
/settings/platform/oauth-clients/[clientId]/edit 257.52 KB 485.17 KB 138.62% (🟢 -1.71%)
/settings/platform/oauth-clients/create 256.66 KB 484.31 KB 138.38% (🟢 -1.72%)
/settings/security/impersonation 265.99 KB 493.65 KB 141.04% (🟢 -1.69%)
/settings/security/password 304.18 KB 531.83 KB 151.95% (🟢 -1.66%)
/settings/security/sso 270.86 KB 498.52 KB 142.43% (🟢 -1.69%)
/settings/security/two-factor-auth 269.47 KB 497.13 KB 142.04% (🟢 -1.69%)
/settings/teams 260.32 KB 487.97 KB 139.42% (🟢 -1.69%)
/settings/teams/[id]/appearance 273.54 KB 501.2 KB 143.20% (🟢 -1.64%)
/settings/teams/[id]/billing 260.82 KB 488.48 KB 139.57% (🟢 -1.69%)
/settings/teams/[id]/members 378.37 KB 606.03 KB 173.15% (🟢 -1.68%)
/settings/teams/[id]/profile 472.86 KB 700.51 KB 200.15% (🟢 -1.66%)
/settings/teams/new 193.05 KB 420.71 KB 120.20% (🟢 -1.81%)
/teams 254.34 KB 481.99 KB 137.71% (🟢 -1.71%)
/upgrade 254.46 KB 482.12 KB 137.75% (🟢 -1.71%)
/video/[uid] 291.31 KB 518.97 KB 148.28% (🟢 -0.15%)
/workflows 286.36 KB 514.02 KB 146.86% (🟢 -1.65%)
/workflows/[workflow] 414.66 KB 642.31 KB 183.52% (🟢 -1.43%)
Details

Only the gzipped size is provided here based on an expert tip.

First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If next/link is used, subsequent page loads would only need to download that page's bundle (the number in the "Size" column), since the global bundle has already been downloaded.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

The "Budget %" column shows what percentage of your performance budget the First Load total takes up. For example, if your budget was 100kb, and a given page's first load size was 10kb, it would be 10% of your budget. You can also see how much this has increased or decreased compared to the base branch of your PR. If this percentage has increased by 20% or more, there will be a red status indicator applied, indicating that special attention should be given to this. If you see "+/-

github-actions[bot] avatar May 16 '24 23:05 github-actions[bot]

Current Playwright Test Results Summary

✅ 321 Passing - ⚠️ 13 Flaky

Run may still be in progress, this comment will be updated as current testing workflow or job completes...

(Last updated on 05/18/2024 06:12:57am UTC)

Run Details

Running Workflow PR Update on Github Actions

Commit: 2f0fdf0d6507984e56d1515d634c1e50d9ea573c

Started: 05/18/2024 06:10:46am UTC

⚠️ Flakes

📄   apps/web/playwright/booking-seats.e2e.ts • 1 Flake

Test Case Results

Test Case Last 7 days Failures Last 7 days Flakes
Reschedule for booking with seats If rescheduled/cancelled booking with seats it should display the correct number of seats
Retry 1Initial Attempt
0% (0) 0 / 212 runs
failed over last 7 days
1.89% (4) 4 / 212 runs
flaked over last 7 days

📄   apps/web/playwright/profile.e2e.ts • 1 Flake

Test Case Results

Test Case Last 7 days Failures Last 7 days Flakes
Update Profile Can update a users email (verification enabled)
Retry 2Retry 1Initial Attempt
38.02% (92) 92 / 242 runs
failed over last 7 days
33.47% (81) 81 / 242 runs
flaked over last 7 days

📄   packages/app-store/routing-forms/playwright/tests/basic.e2e.ts • 1 Flake

Test Case Results

Test Case Last 7 days Failures Last 7 days Flakes
Routing Forms Seeded Routing Form Test preview should return correct route
Retry 1Initial Attempt
0.91% (2) 2 / 219 runs
failed over last 7 days
31.05% (68) 68 / 219 runs
flaked over last 7 days

📄   apps/web/playwright/event-types.e2e.ts • 1 Flake

Test Case Results

Test Case Last 7 days Failures Last 7 days Flakes
Event Types tests -- legacy user Different Locations Tests Can remove location from multiple locations that are saved
Retry 1Initial Attempt
4.48% (10) 10 / 223 runs
failed over last 7 days
19.28% (43) 43 / 223 runs
flaked over last 7 days

📄   apps/web/playwright/managedBooking/advancedOptions.e2e.ts • 1 Flake

Test Case Results

Test Case Last 7 days Failures Last 7 days Flakes
Check advanced options in a managed team event type Check advanced options in a managed team event type without offer seats
Retry 1Initial Attempt
0.45% (1) 1 / 220 run
failed over last 7 days
48.18% (106) 106 / 220 runs
flaked over last 7 days

📄   apps/web/playwright/signup.e2e.ts • 1 Flake

Test Case Results

Test Case Last 7 days Failures Last 7 days Flakes
Signup Flow Test Email verification sent if enabled
Retry 1Initial Attempt
0.85% (2) 2 / 234 runs
failed over last 7 days
25.64% (60) 60 / 234 runs
flaked over last 7 days

📄   packages/embeds/embed-core/playwright/tests/namespacing.e2e.ts • 4 Flakes

Top 1 Common Error Messages

null

4 Test Cases Affected

Test Case Results

Test Case Last 7 days Failures Last 7 days Flakes
Namespacing Inline Embed Add inline embed using a namespace without reload
Retry 1Initial Attempt
0.46% (1) 1 / 219 run
failed over last 7 days
60.27% (132) 132 / 219 runs
flaked over last 7 days
Namespacing Inline Embed Double install Embed Snippet with inline embed without a namespace(i.e. default namespace)
Retry 1Initial Attempt
0% (0) 0 / 219 runs
failed over last 7 days
63.01% (138) 138 / 219 runs
flaked over last 7 days
Namespacing Inline Embed Double install Embed Snippet with inline embed using a namespace
Retry 1Initial Attempt
0.46% (1) 1 / 219 run
failed over last 7 days
60.27% (132) 132 / 219 runs
flaked over last 7 days
Namespacing Different namespaces can have different init configs
Retry 1Initial Attempt
0% (0) 0 / 217 runs
failed over last 7 days
60.37% (131) 131 / 217 runs
flaked over last 7 days

📄   apps/web/playwright/hash-my-url.e2e.ts • 1 Flake

Test Case Results

Test Case Last 7 days Failures Last 7 days Flakes
hash my url generate url hash
Retry 2Retry 1Initial Attempt
5.96% (13) 13 / 218 runs
failed over last 7 days
27.98% (61) 61 / 218 runs
flaked over last 7 days

📄   apps/web/playwright/teams.e2e.ts • 1 Flake

Test Case Results

Test Case Last 7 days Failures Last 7 days Flakes
Teams - NonOrg -- legacy Can create a booking for Round Robin EventType
Retry 2Retry 1Initial Attempt
7.30% (17) 17 / 233 runs
failed over last 7 days
28.76% (67) 67 / 233 runs
flaked over last 7 days

📄   apps/web/playwright/organization/booking.e2e.ts • 1 Flake

Test Case Results

Test Case Last 7 days Failures Last 7 days Flakes
Bookings Team Event Can create a booking for Round Robin EventType
Retry 2Retry 1Initial Attempt
7.89% (18) 18 / 228 runs
failed over last 7 days
27.63% (63) 63 / 228 runs
flaked over last 7 days

View Detailed Build Results


deploysentinel[bot] avatar May 17 '24 07:05 deploysentinel[bot]

Putting this back in draft until we have the proper discussion around Bull

keithwillcode avatar May 17 '24 16:05 keithwillcode

need to change the logic to increment usage of managed user instead of relying on oauth client id ,

ThyMinimalDev avatar May 30 '24 14:05 ThyMinimalDev

@ThyMinimalDev Curious if you think we could achieve the same result by having a cron running every X minutes that calculates number of bookings completed and updates usage?

With that approach, we don't need to handle all this logic to chase down the message that was pushed to the queue in the future.

keithwillcode avatar Jun 04 '24 15:06 keithwillcode

@ThyMinimalDev Curious if you think we could achieve the same result by having a cron running every X minutes that calculates number of bookings completed and updates usage?

With that approach, we don't need to handle all this logic to chase down the message that was pushed to the queue in the future.

@ThyMinimalDev Curious if you think we could achieve the same result by having a cron running every X minutes that calculates number of bookings completed and updates usage?

With that approach, we don't need to handle all this logic to chase down the message that was pushed to the queue in the future.

A cron is a good option as well, we could have it look at the non cancelled booking of managed users that are in the past, we would need to add en entry in the database to index and filter the ones that have not yet been counted toward usage

I don't think we would need to worry about stripe rate limiting until some time

ThyMinimalDev avatar Jun 04 '24 15:06 ThyMinimalDev

need to add en entry in the database to index and filter the ones that have not yet been counted toward usage

Would we actually need this if you can just compare the count of the current bookings - even if you keep a running count elsewhere - redis for example?

Then every billing period we just compare the current usage to the value we have in redis and charge accordingly. I was just thinking of ways to do this without queues as it feels weird if i booking is 3 months in advance, do i want that job sitting waiting to run for that long?

sean-brydon avatar Jun 04 '24 16:06 sean-brydon

need to add en entry in the database to index and filter the ones that have not yet been counted toward usage

Would we actually need this if you can just compare the count of the current bookings - even if you keep a running count elsewhere - redis for example?

Then every billing period we just compare the current usage to the value we have in redis and charge accordingly. I was just thinking of ways to do this without queues as it feels weird if i booking is 3 months in advance, do i want that job sitting waiting to run for that long?

that's a good idea, only difficulty I can see is that everyone has different billing cycles

in the end I think the complexity is same-same, but different

ThyMinimalDev avatar Jun 04 '24 18:06 ThyMinimalDev

need to add en entry in the database to index and filter the ones that have not yet been counted toward usage

Would we actually need this if you can just compare the count of the current bookings - even if you keep a running count elsewhere - redis for example? Then every billing period we just compare the current usage to the value we have in redis and charge accordingly. I was just thinking of ways to do this without queues as it feels weird if i booking is 3 months in advance, do i want that job sitting waiting to run for that long?

that's a good idea, only difficulty I can see is that everyone has different billing cycles

in the end I think the complexity is same-same, but different

Agreed - I just wonder if that is a easier / better approach than doing it via canceling a job.

I dont think billing cycles are an issue here if we already have a cron running every day to update this "count" we can check if its like a day before the billing date for that subscription then push the usage record to stripe?

Should probably be an RFC where we come up with a standard to do this cause private-api needs it too

sean-brydon avatar Jun 04 '24 18:06 sean-brydon

I think the ea

need to add en entry in the database to index and filter the ones that have not yet been counted toward usage

Would we actually need this if you can just compare the count of the current bookings - even if you keep a running count elsewhere - redis for example? Then every billing period we just compare the current usage to the value we have in redis and charge accordingly. I was just thinking of ways to do this without queues as it feels weird if i booking is 3 months in advance, do i want that job sitting waiting to run for that long?

that's a good idea, only difficulty I can see is that everyone has different billing cycles in the end I think the complexity is same-same, but different

Agreed - I just wonder if that is a easier / better approach than doing it via canceling a job.

I dont think billing cycles are an issue here if we already have a cron running every day to update this "count" we can check if its like a day before the billing date for that subscription then push the usage record to stripe?

Should probably be an RFC where we come up with a standard to do this cause private-api needs it too

If we don't want to use jobs, the easiest is to increment a count in a redis store, and have a cron that runs often enough to push the usage to stripe and reset it to 0, that way we don't to worry about billing cycles

ThyMinimalDev avatar Jun 04 '24 18:06 ThyMinimalDev

This PR is being marked as stale due to inactivity.

github-actions[bot] avatar Jul 02 '24 00:07 github-actions[bot]

ready for review

ThyMinimalDev avatar Jul 23 '24 12:07 ThyMinimalDev

Screenshot 2024-07-24 at 17 23 41

ThyMinimalDev avatar Jul 24 '24 14:07 ThyMinimalDev