Skip to content

Commit 73de288

Browse files
author
Lasim
committed
refactor(backend): improve token cleanup service logging and initialization
1 parent 1928400 commit 73de288

File tree

6 files changed

+68
-23
lines changed

6 files changed

+68
-23
lines changed

services/backend/src/index.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { createServer } from './server'
22
import { displayStartupBanner } from './utils/banner'
3-
import { TokenCleanupService } from './services/tokenCleanupService'
43

54
const start = async () => {
65
try {
@@ -13,9 +12,6 @@ const start = async () => {
1312
// Display the fancy startup banner
1413
displayStartupBanner(port, server.log)
1514

16-
// Start background services
17-
TokenCleanupService.start()
18-
1915
// Also log using the standard logger (useful for log files)
2016
server.log.info(`DeployStack server started on port ${port}`)
2117
} catch (err) {

services/backend/src/routes/satellites/registration-tokens.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
12
import { type FastifyInstance } from 'fastify';
23
import { SatelliteTokenService } from '../../services/satelliteTokenService';
34
import { requireGlobalAdmin, requireTeamPermission, requireAuthentication } from '../../middleware/roleMiddleware';
@@ -208,7 +209,7 @@ export default async function registrationTokenRoutes(server: FastifyInstance) {
208209
error: 'Failed to generate registration token'
209210
};
210211
const jsonString = JSON.stringify(errorResponse);
211-
return reply.status(500).type('application/json').send(jsonString);
212+
return reply.status(500 as any).type('application/json').send(jsonString);
212213
}
213214
});
214215

@@ -303,7 +304,7 @@ export default async function registrationTokenRoutes(server: FastifyInstance) {
303304
error: 'Failed to generate registration token'
304305
};
305306
const jsonString = JSON.stringify(errorResponse);
306-
return reply.status(500).type('application/json').send(jsonString);
307+
return reply.status(500 as any).type('application/json').send(jsonString);
307308
}
308309
});
309310

@@ -346,7 +347,7 @@ export default async function registrationTokenRoutes(server: FastifyInstance) {
346347
error: 'Failed to list tokens'
347348
};
348349
const jsonString = JSON.stringify(errorResponse);
349-
return reply.status(500).type('application/json').send(jsonString);
350+
return reply.status(500 as any).type('application/json').send(jsonString);
350351
}
351352
});
352353

@@ -399,7 +400,7 @@ export default async function registrationTokenRoutes(server: FastifyInstance) {
399400
error: 'Failed to list tokens'
400401
};
401402
const jsonString = JSON.stringify(errorResponse);
402-
return reply.status(500).type('application/json').send(jsonString);
403+
return reply.status(500 as any).type('application/json').send(jsonString);
403404
}
404405
});
405406

@@ -482,7 +483,7 @@ export default async function registrationTokenRoutes(server: FastifyInstance) {
482483
error: 'Failed to revoke token'
483484
};
484485
const jsonString = JSON.stringify(errorResponse);
485-
return reply.status(500).type('application/json').send(jsonString);
486+
return reply.status(500 as any).type('application/json').send(jsonString);
486487
}
487488
});
488489
}

services/backend/src/server.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,25 @@ export async function initializeDatabaseDependentServices(
151151
server.log.warn('⚠️ Continuing without MCP User Configuration Service due to error');
152152
}
153153

154+
// Start Token Cleanup Service (only after database is ready)
155+
try {
156+
server.log.debug('Starting Token Cleanup Service...');
157+
const { TokenCleanupService } = await import('./services/tokenCleanupService');
158+
TokenCleanupService.start(server.log);
159+
server.log.debug('Token Cleanup Service started');
160+
} catch (tokenCleanupError) {
161+
server.log.error({
162+
error: tokenCleanupError,
163+
message: tokenCleanupError instanceof Error ? tokenCleanupError.message : 'Unknown error',
164+
stack: tokenCleanupError instanceof Error ? tokenCleanupError.stack : 'No stack trace'
165+
}, 'Token Cleanup Service failed to start:');
166+
// Don't throw - continue with startup but log the error
167+
server.log.warn('Continuing without Token Cleanup Service due to error');
168+
}
169+
154170
// Initialize global settings with comprehensive debugging
155171
try {
156-
server.log.debug('🔄 Starting global settings initialization...');
172+
server.log.debug('Starting global settings initialization...');
157173

158174
// Check database status before proceeding
159175
const dbStatus = getDbStatus();

services/backend/src/services/satelliteTokenService.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { nanoid } from 'nanoid';
22
import { hash, verify } from '@node-rs/argon2';
33
import { getDb } from '../db';
4-
import { satelliteRegistrationTokens, teams, authUser } from '../db/schema.sqlite';
4+
import { satelliteRegistrationTokens } from '../db/schema.sqlite';
55
import { eq, and, lt } from 'drizzle-orm';
66
import { SimpleJWT, TokenExpiredError } from '../utils/jwt';
77
import type {
@@ -115,6 +115,7 @@ export class SatelliteTokenService {
115115
try {
116116
payload = SimpleJWT.verify(jwtToken, this.JWT_SECRET) as JWTPayload;
117117
} catch (jwtError) {
118+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
118119
if (jwtError instanceof TokenExpiredError || (jwtError as any).name === 'TokenExpiredError') {
119120
return { valid: false, error: 'Token has expired' };
120121
}

services/backend/src/services/tokenCleanupService.ts

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { SatelliteTokenService } from './satelliteTokenService';
2+
import type { FastifyBaseLogger } from 'fastify';
23

34
/**
45
* Background service for cleaning up expired satellite registration tokens
@@ -7,33 +8,49 @@ import { SatelliteTokenService } from './satelliteTokenService';
78
export class TokenCleanupService {
89
private static intervalId: NodeJS.Timeout | null = null;
910
private static readonly DEFAULT_CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
11+
private static logger: FastifyBaseLogger | null = null;
1012

1113
/**
1214
* Start periodic cleanup of expired tokens
1315
* Runs every hour by default
1416
*/
15-
static start(intervalMs: number = this.DEFAULT_CLEANUP_INTERVAL_MS) {
17+
static start(logger: FastifyBaseLogger, intervalMs: number = this.DEFAULT_CLEANUP_INTERVAL_MS) {
1618
if (this.intervalId) {
17-
console.log('🧹 Token cleanup service already running');
19+
logger.warn({
20+
operation: 'token_cleanup_start',
21+
status: 'already_running'
22+
}, '🧹 Token cleanup service already running');
1823
return;
1924
}
2025

26+
this.logger = logger;
27+
2128
// Run cleanup immediately on start
2229
this.runCleanup().catch(error => {
23-
console.error('Initial token cleanup failed:', error);
30+
logger.error({
31+
operation: 'token_cleanup_initial',
32+
error
33+
}, 'Initial token cleanup failed');
2434
});
2535

2636
// Schedule periodic cleanup
2737
this.intervalId = setInterval(async () => {
2838
try {
2939
await this.runCleanup();
3040
} catch (error) {
31-
console.error('Token cleanup failed:', error);
41+
logger.error({
42+
operation: 'token_cleanup_periodic',
43+
error
44+
}, 'Token cleanup failed');
3245
}
3346
}, intervalMs);
3447

3548
const intervalHours = Math.round(intervalMs / (60 * 60 * 1000));
36-
console.log(`🕒 Token cleanup service started (runs every ${intervalHours} hour${intervalHours !== 1 ? 's' : ''})`);
49+
logger.info({
50+
operation: 'token_cleanup_start',
51+
intervalMs,
52+
intervalHours
53+
}, `🕒 Token cleanup service started (runs every ${intervalHours} hour${intervalHours !== 1 ? 's' : ''})`);
3754
}
3855

3956
/**
@@ -43,7 +60,12 @@ export class TokenCleanupService {
4360
if (this.intervalId) {
4461
clearInterval(this.intervalId);
4562
this.intervalId = null;
46-
console.log('🛑 Token cleanup service stopped');
63+
64+
if (this.logger) {
65+
this.logger.info({
66+
operation: 'token_cleanup_stop'
67+
}, '🛑 Token cleanup service stopped');
68+
}
4769
}
4870
}
4971

@@ -53,12 +75,20 @@ export class TokenCleanupService {
5375
static async runCleanup(): Promise<number> {
5476
try {
5577
const deletedCount = await SatelliteTokenService.cleanupExpiredTokens();
56-
if (deletedCount > 0) {
57-
console.log(`🧹 Cleaned up ${deletedCount} expired satellite registration token${deletedCount !== 1 ? 's' : ''}`);
78+
if (deletedCount > 0 && this.logger) {
79+
this.logger.info({
80+
operation: 'token_cleanup_run',
81+
deletedCount
82+
}, `🧹 Cleaned up ${deletedCount} expired satellite registration token${deletedCount !== 1 ? 's' : ''}`);
5883
}
5984
return deletedCount;
6085
} catch (error) {
61-
console.error('Token cleanup failed:', error);
86+
if (this.logger) {
87+
this.logger.error({
88+
operation: 'token_cleanup_run',
89+
error
90+
}, 'Token cleanup failed');
91+
}
6292
throw error;
6393
}
6494
}
@@ -76,8 +106,8 @@ export class TokenCleanupService {
76106
/**
77107
* Restart the cleanup service with new interval
78108
*/
79-
static restart(intervalMs?: number) {
109+
static restart(logger: FastifyBaseLogger, intervalMs?: number) {
80110
this.stop();
81-
this.start(intervalMs);
111+
this.start(logger, intervalMs);
82112
}
83113
}

services/backend/src/utils/jwt.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { createHmac, randomBytes, timingSafeEqual } from 'crypto';
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import { createHmac, timingSafeEqual } from 'crypto';
23

34
/**
45
* Simple JWT implementation using Node.js crypto

0 commit comments

Comments
 (0)