Преглед изворни кода

Add access token deletion cron service and configuration

reiji-h пре 1 година
родитељ
комит
cd08258c96

+ 2 - 0
apps/app/src/server/crowi/index.js

@@ -13,6 +13,7 @@ import { LdapUserGroupSyncService } from '~/features/external-user-group/server/
 import { startCronIfEnabled as startOpenaiCronIfEnabled } from '~/features/openai/server/services/cron';
 import QuestionnaireService from '~/features/questionnaire/server/service/questionnaire';
 import QuestionnaireCronService from '~/features/questionnaire/server/service/questionnaire-cron';
+import { startCron as startAccessTokenCron } from '~/server/service/access-token';
 import { getGrowiVersion } from '~/utils/growi-version';
 import loggerFactory from '~/utils/logger';
 import { projectRoot } from '~/utils/project-dir-utils';
@@ -359,6 +360,7 @@ Crowi.prototype.setupCron = function() {
   this.questionnaireCronService.startCron();
 
   startOpenaiCronIfEnabled();
+  startAccessTokenCron();
 };
 
 Crowi.prototype.setupQuestionnaireService = function() {

+ 64 - 0
apps/app/src/server/service/access-token/access-token-deletion-cron.ts

@@ -0,0 +1,64 @@
+import nodeCron from 'node-cron';
+
+import { AccessToken } from '~/server/models/access-token';
+import { configManager } from '~/server/service/config-manager';
+import loggerFactory from '~/utils/logger';
+import { getRandomIntInRange } from '~/utils/rand';
+
+const logger = loggerFactory('growi:service:access-token-deletion-cron');
+
+export class AccessTokenDeletionCronService {
+
+  cronJob: nodeCron.ScheduledTask;
+
+  // デフォルトで毎日深夜0時に実行 (UTC で 15:00)
+  accessTokenDeletionCronExpression = '0 15 * * *';
+
+  // デフォルトで最大30分のランダム遅延
+  accessTokenDeletionCronMaxMinutesUntilRequest = 30;
+
+  sleep = (msec: number): Promise<void> => new Promise(resolve => setTimeout(resolve, msec));
+
+  startCron(): void {
+    this.accessTokenDeletionCronExpression = configManager.getConfig('accessToken:deletionCronExpression');
+    this.accessTokenDeletionCronMaxMinutesUntilRequest = configManager.getConfig('accessToken:deletionCronMaxMinutesUntilRequest');
+
+    this.cronJob?.stop();
+    this.cronJob = this.generateCronJob();
+    this.cronJob.start();
+
+    logger.info('Access token deletion cron started');
+  }
+
+  private async executeJob(): Promise<void> {
+    try {
+      await AccessToken.deleteExpiredToken();
+      logger.info('Expired access tokens have been deleted');
+    }
+    catch (e) {
+      logger.error('Failed to delete expired access tokens:', e);
+    }
+  }
+
+  private generateCronJob() {
+    return nodeCron.schedule(this.accessTokenDeletionCronExpression, async() => {
+      try {
+        // Random fractional sleep to distribute request timing among GROWI apps
+        const randomMilliseconds = getRandomIntInRange(0, this.accessTokenDeletionCronMaxMinutesUntilRequest) * 60 * 1000;
+        await this.sleep(randomMilliseconds);
+
+        await this.executeJob();
+      }
+      catch (e) {
+        logger.error('Error occurred during access token deletion cron job:', e);
+      }
+    });
+  }
+
+}
+
+export const startCron = (): void => {
+  logger.info('Starting cron service for access token deletion');
+  const accessTokenDeletionCronService = new AccessTokenDeletionCronService();
+  accessTokenDeletionCronService.startCron();
+};

+ 1 - 0
apps/app/src/server/service/access-token/index.ts

@@ -0,0 +1 @@
+export { AccessTokenDeletionCronService, startCron } from './access-token-deletion-cron';

+ 13 - 0
apps/app/src/server/service/config-manager/config-definition.ts

@@ -318,6 +318,9 @@ export const CONFIG_KEYS = [
   'env:useOnlyEnvVars:gcs',
   'env:useOnlyEnvVars:azure',
 
+  // Access Token Settings
+  'accessToken:deletionCronExpression',
+  'accessToken:deletionCronMaxMinutesUntilRequest',
 ] as const;
 
 
@@ -325,6 +328,16 @@ export type ConfigKey = (typeof CONFIG_KEYS)[number];
 
 
 export const CONFIG_DEFINITIONS = {
+  // Access Token Settings
+  'accessToken:deletionCronExpression': defineConfig<string>({
+    envVarName: 'ACCESS_TOKEN_DELETION_CRON_EXPRESSION',
+    defaultValue: '0 15 * * *',
+  }),
+  'accessToken:deletionCronMaxMinutesUntilRequest': defineConfig<number>({
+    envVarName: 'ACCESS_TOKEN_DELETION_CRON_MAX_MINUTES_UNTIL_REQUEST',
+    defaultValue: 30,
+  }),
+
   // Auto Install Settings
   'autoInstall:adminUsername': defineConfig<string | undefined>({
     envVarName: 'AUTO_INSTALL_ADMIN_USERNAME',