Nick: fixed prettier
This commit is contained in:
@@ -23,7 +23,12 @@ const AUTO_RECHARGE_COOLDOWN = 300; // 5 minutes in seconds
|
||||
export async function autoCharge(
|
||||
chunk: AuthCreditUsageChunk,
|
||||
autoRechargeThreshold: number
|
||||
): Promise<{ success: boolean; message: string; remainingCredits: number; chunk: AuthCreditUsageChunk }> {
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
message: string;
|
||||
remainingCredits: number;
|
||||
chunk: AuthCreditUsageChunk;
|
||||
}> {
|
||||
const resource = `auto-recharge:${chunk.team_id}`;
|
||||
const cooldownKey = `auto-recharge-cooldown:${chunk.team_id}`;
|
||||
|
||||
@@ -32,145 +37,162 @@ export async function autoCharge(
|
||||
// Another check to prevent race conditions, double charging - cool down of 5 minutes
|
||||
const cooldownValue = await getValue(cooldownKey);
|
||||
if (cooldownValue) {
|
||||
logger.info(`Auto-recharge for team ${chunk.team_id} is in cooldown period`);
|
||||
logger.info(
|
||||
`Auto-recharge for team ${chunk.team_id} is in cooldown period`
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
message: "Auto-recharge is in cooldown period",
|
||||
remainingCredits: chunk.remaining_credits,
|
||||
chunk,
|
||||
chunk
|
||||
};
|
||||
}
|
||||
|
||||
// Use a distributed lock to prevent concurrent auto-charge attempts
|
||||
return await redlock.using([resource], 5000, async (signal) : Promise<{ success: boolean; message: string; remainingCredits: number; chunk: AuthCreditUsageChunk }> => {
|
||||
// Recheck the condition inside the lock to prevent race conditions
|
||||
const updatedChunk = await getACUC(chunk.api_key, false, false);
|
||||
if (
|
||||
updatedChunk &&
|
||||
updatedChunk.remaining_credits < autoRechargeThreshold
|
||||
) {
|
||||
if (chunk.sub_user_id) {
|
||||
// Fetch the customer's Stripe information
|
||||
const { data: customer, error: customersError } =
|
||||
await supabase_service
|
||||
.from("customers")
|
||||
.select("id, stripe_customer_id")
|
||||
.eq("id", chunk.sub_user_id)
|
||||
.single();
|
||||
|
||||
if (customersError) {
|
||||
logger.error(`Error fetching customer data: ${customersError}`);
|
||||
return {
|
||||
success: false,
|
||||
message: "Error fetching customer data",
|
||||
remainingCredits: chunk.remaining_credits,
|
||||
chunk,
|
||||
};
|
||||
}
|
||||
return await redlock.using(
|
||||
[resource],
|
||||
5000,
|
||||
async (
|
||||
signal
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
message: string;
|
||||
remainingCredits: number;
|
||||
chunk: AuthCreditUsageChunk;
|
||||
}> => {
|
||||
// Recheck the condition inside the lock to prevent race conditions
|
||||
const updatedChunk = await getACUC(chunk.api_key, false, false);
|
||||
if (
|
||||
updatedChunk &&
|
||||
updatedChunk.remaining_credits < autoRechargeThreshold
|
||||
) {
|
||||
if (chunk.sub_user_id) {
|
||||
// Fetch the customer's Stripe information
|
||||
const { data: customer, error: customersError } =
|
||||
await supabase_service
|
||||
.from("customers")
|
||||
.select("id, stripe_customer_id")
|
||||
.eq("id", chunk.sub_user_id)
|
||||
.single();
|
||||
|
||||
if (customer && customer.stripe_customer_id) {
|
||||
let issueCreditsSuccess = false;
|
||||
// Attempt to create a payment intent
|
||||
const paymentStatus = await createPaymentIntent(
|
||||
chunk.team_id,
|
||||
customer.stripe_customer_id
|
||||
);
|
||||
|
||||
// If payment is successful or requires further action, issue credits
|
||||
if (
|
||||
paymentStatus.return_status === "succeeded" ||
|
||||
paymentStatus.return_status === "requires_action"
|
||||
) {
|
||||
issueCreditsSuccess = await issueCredits(
|
||||
if (customersError) {
|
||||
logger.error(`Error fetching customer data: ${customersError}`);
|
||||
return {
|
||||
success: false,
|
||||
message: "Error fetching customer data",
|
||||
remainingCredits: chunk.remaining_credits,
|
||||
chunk
|
||||
};
|
||||
}
|
||||
|
||||
if (customer && customer.stripe_customer_id) {
|
||||
let issueCreditsSuccess = false;
|
||||
// Attempt to create a payment intent
|
||||
const paymentStatus = await createPaymentIntent(
|
||||
chunk.team_id,
|
||||
AUTO_RECHARGE_CREDITS
|
||||
);
|
||||
}
|
||||
|
||||
// Record the auto-recharge transaction
|
||||
await supabase_service.from("auto_recharge_transactions").insert({
|
||||
team_id: chunk.team_id,
|
||||
initial_payment_status: paymentStatus.return_status,
|
||||
credits_issued: issueCreditsSuccess ? AUTO_RECHARGE_CREDITS : 0,
|
||||
stripe_charge_id: paymentStatus.charge_id,
|
||||
});
|
||||
|
||||
// Send a notification if credits were successfully issued
|
||||
if (issueCreditsSuccess) {
|
||||
await sendNotification(
|
||||
chunk.team_id,
|
||||
NotificationType.AUTO_RECHARGE_SUCCESS,
|
||||
chunk.sub_current_period_start,
|
||||
chunk.sub_current_period_end,
|
||||
chunk,
|
||||
true
|
||||
customer.stripe_customer_id
|
||||
);
|
||||
|
||||
// Set cooldown period
|
||||
await setValue(cooldownKey, 'true', AUTO_RECHARGE_COOLDOWN);
|
||||
}
|
||||
|
||||
// Reset ACUC cache to reflect the new credit balance
|
||||
const cacheKeyACUC = `acuc_${chunk.api_key}`;
|
||||
await deleteKey(cacheKeyACUC);
|
||||
|
||||
if (process.env.SLACK_ADMIN_WEBHOOK_URL) {
|
||||
const webhookCooldownKey = `webhook_cooldown_${chunk.team_id}`;
|
||||
const isInCooldown = await getValue(webhookCooldownKey);
|
||||
|
||||
if (!isInCooldown) {
|
||||
sendSlackWebhook(
|
||||
`Auto-recharge: Team ${chunk.team_id}. ${AUTO_RECHARGE_CREDITS} credits added. Payment status: ${paymentStatus.return_status}.`,
|
||||
false,
|
||||
process.env.SLACK_ADMIN_WEBHOOK_URL
|
||||
).catch((error) => {
|
||||
logger.debug(`Error sending slack notification: ${error}`);
|
||||
});
|
||||
|
||||
// Set cooldown for 1 hour
|
||||
await setValue(webhookCooldownKey, 'true', 60 * 60);
|
||||
// If payment is successful or requires further action, issue credits
|
||||
if (
|
||||
paymentStatus.return_status === "succeeded" ||
|
||||
paymentStatus.return_status === "requires_action"
|
||||
) {
|
||||
issueCreditsSuccess = await issueCredits(
|
||||
chunk.team_id,
|
||||
AUTO_RECHARGE_CREDITS
|
||||
);
|
||||
}
|
||||
|
||||
// Record the auto-recharge transaction
|
||||
await supabase_service.from("auto_recharge_transactions").insert({
|
||||
team_id: chunk.team_id,
|
||||
initial_payment_status: paymentStatus.return_status,
|
||||
credits_issued: issueCreditsSuccess ? AUTO_RECHARGE_CREDITS : 0,
|
||||
stripe_charge_id: paymentStatus.charge_id
|
||||
});
|
||||
|
||||
// Send a notification if credits were successfully issued
|
||||
if (issueCreditsSuccess) {
|
||||
await sendNotification(
|
||||
chunk.team_id,
|
||||
NotificationType.AUTO_RECHARGE_SUCCESS,
|
||||
chunk.sub_current_period_start,
|
||||
chunk.sub_current_period_end,
|
||||
chunk,
|
||||
true
|
||||
);
|
||||
|
||||
// Set cooldown period
|
||||
await setValue(cooldownKey, "true", AUTO_RECHARGE_COOLDOWN);
|
||||
}
|
||||
|
||||
// Reset ACUC cache to reflect the new credit balance
|
||||
const cacheKeyACUC = `acuc_${chunk.api_key}`;
|
||||
await deleteKey(cacheKeyACUC);
|
||||
|
||||
if (process.env.SLACK_ADMIN_WEBHOOK_URL) {
|
||||
const webhookCooldownKey = `webhook_cooldown_${chunk.team_id}`;
|
||||
const isInCooldown = await getValue(webhookCooldownKey);
|
||||
|
||||
if (!isInCooldown) {
|
||||
sendSlackWebhook(
|
||||
`Auto-recharge: Team ${chunk.team_id}. ${AUTO_RECHARGE_CREDITS} credits added. Payment status: ${paymentStatus.return_status}.`,
|
||||
false,
|
||||
process.env.SLACK_ADMIN_WEBHOOK_URL
|
||||
).catch((error) => {
|
||||
logger.debug(`Error sending slack notification: ${error}`);
|
||||
});
|
||||
|
||||
// Set cooldown for 1 hour
|
||||
await setValue(webhookCooldownKey, "true", 60 * 60);
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
message: "Auto-recharge successful",
|
||||
remainingCredits:
|
||||
chunk.remaining_credits + AUTO_RECHARGE_CREDITS,
|
||||
chunk: {
|
||||
...chunk,
|
||||
remaining_credits:
|
||||
chunk.remaining_credits + AUTO_RECHARGE_CREDITS
|
||||
}
|
||||
};
|
||||
} else {
|
||||
logger.error("No Stripe customer ID found for user");
|
||||
return {
|
||||
success: false,
|
||||
message: "No Stripe customer ID found for user",
|
||||
remainingCredits: chunk.remaining_credits,
|
||||
chunk
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
message: "Auto-recharge successful",
|
||||
remainingCredits: chunk.remaining_credits + AUTO_RECHARGE_CREDITS,
|
||||
chunk: {...chunk, remaining_credits: chunk.remaining_credits + AUTO_RECHARGE_CREDITS},
|
||||
};
|
||||
} else {
|
||||
logger.error("No Stripe customer ID found for user");
|
||||
logger.error("No sub_user_id found in chunk");
|
||||
return {
|
||||
success: false,
|
||||
message: "No Stripe customer ID found for user",
|
||||
message: "No sub_user_id found in chunk",
|
||||
remainingCredits: chunk.remaining_credits,
|
||||
chunk,
|
||||
chunk
|
||||
};
|
||||
}
|
||||
} else {
|
||||
logger.error("No sub_user_id found in chunk");
|
||||
return {
|
||||
success: false,
|
||||
message: "No sub_user_id found in chunk",
|
||||
remainingCredits: chunk.remaining_credits,
|
||||
chunk,
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
message: "No need to auto-recharge",
|
||||
remainingCredits: chunk.remaining_credits,
|
||||
chunk
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
message: "No need to auto-recharge",
|
||||
remainingCredits: chunk.remaining_credits,
|
||||
chunk,
|
||||
};
|
||||
|
||||
});
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error(`Failed to acquire lock for auto-recharge: ${error}`);
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed to acquire lock for auto-recharge",
|
||||
remainingCredits: chunk.remaining_credits,
|
||||
chunk,
|
||||
chunk
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user