batch kill dead clients

This commit is contained in:
Ben
2025-11-21 18:42:00 -05:00
parent ff84d8284f
commit 6f6abe5e2d
2 changed files with 31 additions and 11 deletions
+21 -3
View File
@@ -19,13 +19,31 @@ export class ClientService {
}
public async killDeadClients() {
const batchSize = 500;
return await this.clientRepository
const clients = await this.clientRepository
.createQueryBuilder('client')
.where('client.deletedAt IS NULL')
.andWhere('client.updatedAt < NOW() - INTERVAL \'5 minutes\'')
.orderBy('client.id', 'ASC') // consistent lock order ← prevents deadlocks
.limit(batchSize) // small batches ← prevents lock explosion
.setLock('pessimistic_write') // adds FOR UPDATE SKIP LOCKED
.getMany();
if (clients.length === 0) {
return false; // nothing to do (caller can stop looping)
}
const ids = clients.map(c => c.id);
await this.clientRepository
.createQueryBuilder()
.update(ClientEntity)
.set({ deletedAt: () => "NOW()" })
.where("deletedAt IS NULL AND updatedAt < NOW() - interval '5 minutes' ")
.set({ deletedAt: () => 'NOW()' })
.whereInIds(ids)
.execute();
return true; // tell caller there might be more batches
}
//public async heartbeat(id, hashRate: number, updatedAt: Date) {
+3 -1
View File
@@ -30,7 +30,9 @@ export class AppService implements OnModuleInit {
setInterval(async () => {
console.log('Killing dead clients');
await this.clientService.killDeadClients();
while (await this.clientService.killDeadClients()) {
console.log('Finished killing clients');
}
}, 1000 * 60 * 5);
setInterval(async () => {