feat(sync): harden the Hiboutik sync, share rate limits across instances, update dependencies (#4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,20 +1,25 @@
|
||||
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
|
||||
import { Injectable, OnApplicationShutdown, OnModuleInit } from '@nestjs/common';
|
||||
import { PrismaClient } from './generated/client';
|
||||
import { PrismaPg } from '@prisma/adapter-pg';
|
||||
|
||||
/** Prisma client shared by the whole app (global PrismaModule), connected to `DATABASE_URL` through the pg driver adapter. */
|
||||
@Injectable()
|
||||
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
||||
export class PrismaService extends PrismaClient implements OnModuleInit, OnApplicationShutdown {
|
||||
constructor() {
|
||||
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
|
||||
super({ adapter });
|
||||
// 'minimal': by default, error messages print the query arguments (emails, names, addresses...), which end up in the logs
|
||||
super({ adapter, errorFormat: 'minimal' });
|
||||
}
|
||||
|
||||
async onModuleInit() {
|
||||
await this.$connect();
|
||||
}
|
||||
|
||||
async onModuleDestroy() {
|
||||
/**
|
||||
* Last shutdown hook (after `onModuleDestroy` and `beforeApplicationShutdown`, once the HTTP server is closed):
|
||||
* a synchronization still running is waited for in `beforeApplicationShutdown` and keeps the database until then.
|
||||
*/
|
||||
async onApplicationShutdown() {
|
||||
await this.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ model Customer {
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
dateOfBirth DateTime?
|
||||
/// Kept when removed in Hiboutik (an empty Hiboutik email does not erase it)
|
||||
/// Null when the customer has no email in Hiboutik (erased when removed there)
|
||||
email String?
|
||||
firstName String
|
||||
hiboutikId Int @unique
|
||||
@@ -227,3 +227,19 @@ model OrderLine {
|
||||
|
||||
@@map("order_lines")
|
||||
}
|
||||
|
||||
/// Rate limiting counter shared by every instance (ThrottlerDatabaseStorage): one fixed window per throttler key
|
||||
/// (route + client IP). Not synced from Hiboutik. Rows whose window and block are over are purged regularly.
|
||||
model ThrottlerRecord {
|
||||
/// Key generated by the ThrottlerGuard (hash of route, throttler name and client IP)
|
||||
key String @id
|
||||
/// Requests counted in the current window
|
||||
hits Int
|
||||
/// End of the current window
|
||||
expiresAt DateTime @db.Timestamptz(3)
|
||||
/// End of the block once the limit was exceeded, null when not blocked
|
||||
blockedUntil DateTime? @db.Timestamptz(3)
|
||||
|
||||
@@index([expiresAt])
|
||||
@@map("throttler_records")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user