fix: widen rents.usd_amount column, add webhook alias, silence cron spam

- Migration to ALTER rents.usd_amount from numeric(5,2) to numeric(15,2)
  which was causing "numeric field overflow" 500 errors when saving
  rental prices >= 1000 sats (e.g. 1200 sats)
- Also widen season_rents.usd_amount for consistency
- Add /webhooks/btcpay route alias (BTCPay was posting to /btcpay but
  the endpoint was /btcpay-webhook, causing 404s on payment callbacks)
- Skip ECS autoscaling cron when TRANSCODING_API_URL is not set
  (eliminates "security token invalid" error spam every minute)
- Reduce payment cron from EVERY_MINUTE to EVERY_10_MINUTES to avoid
  429 rate limiting on the BTC price API
- Bump API CACHEBUST to 10

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Dorian
2026-02-13 21:30:29 +00:00
parent 5244fdef50
commit c84c4e92b7
5 changed files with 47 additions and 3 deletions

View File

@@ -0,0 +1,34 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
/**
* Widen the usd_amount columns in rents and season_rents tables.
*
* The original migration (1711564180593) created rents.usd_amount as
* numeric(5,2), which caps at 999.99. Rental prices are stored in
* satoshis (e.g. 1200 sats) and easily exceed 999. The entity definition
* specifies precision 15, scale 2 — this migration aligns the database.
*
* season_rents.usd_amount (created in 1755016652731) has the same
* narrow precision and is updated here for consistency.
*/
export class WidenUsdAmountColumns1776300000000 implements MigrationInterface {
name = 'WidenUsdAmountColumns1776300000000';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "rents" ALTER COLUMN "usd_amount" TYPE numeric(15,2)`,
);
await queryRunner.query(
`ALTER TABLE "season_rents" ALTER COLUMN "usd_amount" TYPE numeric(15,2)`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "rents" ALTER COLUMN "usd_amount" TYPE numeric(5,2)`,
);
await queryRunner.query(
`ALTER TABLE "season_rents" ALTER COLUMN "usd_amount" TYPE numeric(5,2)`,
);
}
}

View File

@@ -159,7 +159,7 @@ export class PaymentService {
};
}
@Cron(CronExpression.EVERY_MINUTE)
@Cron(CronExpression.EVERY_10_MINUTES)
async handlePaymentsCron() {
await Promise.all([
this.handlePayment('watch'),

View File

@@ -102,10 +102,12 @@ export class TranscodingServerService {
Logger.log(`Auto Scaling group scaled to ${desiredCount} instances`);
}
// Run the autoscaling logic every hour
// Run the autoscaling logic every hour (AWS ECS only).
// Skip when using the local FFmpeg worker (no TRANSCODING_API_URL).
@Cron(CronExpression.EVERY_MINUTE)
async autoscaleEcsService() {
if (process.env.ENVIRONMENT !== 'production') return;
if (!process.env.TRANSCODING_API_URL) return;
try {
const queueSize = await this.getQueueSize();
const currentTaskCount = await this.describeService(

View File

@@ -13,6 +13,8 @@ import type { BTCPayWebhookEvent } from 'src/payment/providers/dto/btcpay/btcpay
export class WebhooksController {
constructor(private readonly webhooksService: WebhooksService) {}
// Accept both /webhooks/btcpay-webhook (original) and /webhooks/btcpay
// so the webhook works regardless of which URL is configured in BTCPay.
@Post('btcpay-webhook')
@UseGuards(BTCPayGuard)
async btcpayPayment(@Body() body: BTCPayWebhookEvent) {
@@ -22,4 +24,10 @@ export class WebhooksController {
throw new BadRequestException(error.message);
}
}
@Post('btcpay')
@UseGuards(BTCPayGuard)
async btcpayPaymentAlias(@Body() body: BTCPayWebhookEvent) {
return this.btcpayPayment(body);
}
}

View File

@@ -47,7 +47,7 @@ services:
context: ./backend
dockerfile: Dockerfile
args:
CACHEBUST: "9"
CACHEBUST: "10"
restart: unless-stopped
environment:
# ── Core ─────────────────────────────────────────────