Adds cron endpoint to keep team subscriptions in sync (#7992)
* Fix missing edge case where team is paid but needs to be updated * Reuses cron endpoint to update team subscriptions * Update cron-downgradeUsers.yml * Update payments.ts * Update cron-downgradeUsers.yml * update to 90 writes per second Stripe allow up to 100 per secondpull/7811/head^2
parent
6e856b3bd1
commit
63f51abd84
|
@ -1,11 +1,12 @@
|
|||
name: Cron - downgradeUsers
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# "Scheduled workflows run on the latest commit on the default or base branch."
|
||||
# — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule
|
||||
schedule:
|
||||
# Runs “At minute 0, 15, 30, and 45.” (see https://crontab.guru)
|
||||
- cron: "0,15,30,45 * * * *"
|
||||
# Runs “Every month at 1st (see https://crontab.guru)
|
||||
- cron: "0 0 1 * *"
|
||||
jobs:
|
||||
cron-downgradeUsers:
|
||||
env:
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
import { updateQuantitySubscriptionFromStripe } from "@calcom/features/ee/teams/lib/payments";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const apiKey = req.headers.authorization || req.query.apiKey;
|
||||
if (process.env.CRON_API_KEY !== apiKey) {
|
||||
|
@ -11,10 +14,35 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* Remove this endpoint
|
||||
*/
|
||||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
const pageSize = 90; // Adjust this value based on the total number of teams and the available processing time
|
||||
let pageNumber = 0;
|
||||
|
||||
while (true) {
|
||||
const teams = await prisma.team.findMany({
|
||||
where: {
|
||||
slug: {
|
||||
not: null,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
skip: pageNumber * pageSize,
|
||||
take: pageSize,
|
||||
});
|
||||
|
||||
if (teams.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (const team of teams) {
|
||||
await updateQuantitySubscriptionFromStripe(team.id);
|
||||
await delay(100); // Adjust the delay as needed to avoid rate limiting
|
||||
}
|
||||
|
||||
pageNumber++;
|
||||
}
|
||||
|
||||
res.json({ ok: true });
|
||||
}
|
||||
|
|
|
@ -98,6 +98,9 @@ export const updateQuantitySubscriptionFromStripe = async (teamId: number) => {
|
|||
await stripe.subscriptions.update(subscriptionId, {
|
||||
items: [{ quantity: team.members.length, id: subscriptionItemId }],
|
||||
});
|
||||
console.info(
|
||||
`Updated subscription ${subscriptionId} for team ${teamId} to ${team.members.length} seats.`
|
||||
);
|
||||
} catch (error) {
|
||||
let message = "Unknown error on updateQuantitySubscriptionFromStripe";
|
||||
if (error instanceof Error) message = error.message;
|
||||
|
|
Loading…
Reference in New Issue