diff --git a/packages/app/.env.development b/packages/app/.env.development index c01196b644e..8e6f37f645f 100644 --- a/packages/app/.env.development +++ b/packages/app/.env.development @@ -17,6 +17,7 @@ ELASTICSEARCH_REJECT_UNAUTHORIZED=true HACKMD_URI="http://localhost:3010" HACKMD_URI_FOR_SERVER="http://hackmd:3000" OGP_URI="http://ogp:8088" +GROWI_QUESTIONNAIRE_SERVER_ORIGIN="http://host.docker.internal:3003" # DRAWIO_URI="http://localhost:8080/?offline=1&https=0" # S2SMSG_PUBSUB_SERVER_TYPE=nchan # PUBLISH_OPEN_API=true diff --git a/packages/app/package.json b/packages/app/package.json index b1daa1cc281..69246f4882d 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -137,6 +137,7 @@ "next-superjson": "^0.0.4", "next-themes": "^0.2.0", "nocache": "^3.0.1", + "node-cron": "^3.0.2", "nodemailer": "^6.6.2", "nodemailer-ses-transport": "~1.5.0", "openid-client": "^5.1.2", diff --git a/packages/app/src/server/crowi/index.js b/packages/app/src/server/crowi/index.js index f620dae677d..c79e23f73e8 100644 --- a/packages/app/src/server/crowi/index.js +++ b/packages/app/src/server/crowi/index.js @@ -29,11 +29,13 @@ import PageGrantService from '../service/page-grant'; import PageOperationService from '../service/page-operation'; // eslint-disable-next-line import/no-cycle import { PluginService } from '../service/plugin'; +import QuestionnaireCronService from '../service/questionnaire-cron'; import SearchService from '../service/search'; import { SlackIntegrationService } from '../service/slack-integration'; import { UserNotificationService } from '../service/user-notification'; import { initMongooseGlobalSettings, getMongoUri, mongoOptions } from '../util/mongoose-utils'; + const logger = loggerFactory('growi:crowi'); const httpErrorHandler = require('../middlewares/http-error-handler'); const models = require('../models'); @@ -105,6 +107,7 @@ Crowi.prototype.init = async function() { await this.setupModels(); await this.setupConfigManager(); await this.setupSessionConfig(); + this.setupCron(); // setup messaging services await this.setupS2sMessagingService(); @@ -304,6 +307,10 @@ Crowi.prototype.setupModels = async function() { }); }; +Crowi.prototype.setupCron = function() { + new QuestionnaireCronService(this).setUpCron(); +}; + Crowi.prototype.scanRuntimeVersions = async function() { const self = this; diff --git a/packages/app/src/server/service/config-loader.ts b/packages/app/src/server/service/config-loader.ts index 7002b2c734d..e1bf861bf36 100644 --- a/packages/app/src/server/service/config-loader.ts +++ b/packages/app/src/server/service/config-loader.ts @@ -646,6 +646,24 @@ const ENV_VAR_NAME_TO_CONFIG_INFO = { type: ValueType.STRING, default: null, }, + GROWI_QUESTIONNAIRE_SERVER_ORIGIN: { + ns: 'crowi', + key: 'app:growiQuestionnaireServerOrigin', + type: ValueType.STRING, + default: null, + }, + QUESTIONNAIRE_CRON_SCHEDULE: { + ns: 'crowi', + key: 'app:questionnaireCronSchedule', + type: ValueType.STRING, + default: '0 22 * * *', + }, + QUESTIONNAIRE_CRON_MAX_HOURS_UNTIL_REQUEST: { + ns: 'crowi', + key: 'app:questionnaireCronMaxHoursUntilRequest', + type: ValueType.NUMBER, + default: 4, + }, }; diff --git a/packages/app/src/server/service/questionnaire-cron.ts b/packages/app/src/server/service/questionnaire-cron.ts new file mode 100644 index 00000000000..c0a562b5a5c --- /dev/null +++ b/packages/app/src/server/service/questionnaire-cron.ts @@ -0,0 +1,48 @@ +import axiosRetry from 'axios-retry'; + +import { getRandomIntInRange } from '~/utils/rand'; +import { sleep } from '~/utils/sleep'; + +const axios = require('axios').default; +const nodeCron = require('node-cron'); + +axiosRetry(axios, { retries: 3 }); + +class QuestionnaireCronService { + + crowi: any; + + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types + constructor(crowi) { + this.crowi = crowi; + } + + setUpCron(): void { + const cronSchedule = this.crowi.configManager?.getConfig('crowi', 'app:questionnaireCronSchedule'); + const maxHoursUntilRequest = this.crowi.configManager?.getConfig('crowi', 'app:questionnaireCronMaxHoursUntilRequest'); + + const maxSecondsUntilRequest = maxHoursUntilRequest * 60 * 60; + this.questionnaireOrderGetCron(cronSchedule, maxSecondsUntilRequest); + } + + questionnaireOrderGetCron(cronSchedule: string, maxSecondsUntilRequest: number): void { + const growiQuestionnaireServerOrigin = this.crowi.configManager?.getConfig('crowi', 'app:growiQuestionnaireServerOrigin'); + nodeCron.schedule(cronSchedule, async() => { + const secToSleep = getRandomIntInRange(0, maxSecondsUntilRequest); + + await sleep(secToSleep * 1000); + + try { + const response = await axios.get(`${growiQuestionnaireServerOrigin}/questionnaire-order/index`); + console.log(response.data); + } + catch (e) { + console.log(e); + } + + }).start(); + } + +} + +export default QuestionnaireCronService; diff --git a/packages/app/src/utils/rand.ts b/packages/app/src/utils/rand.ts new file mode 100644 index 00000000000..28c273443b1 --- /dev/null +++ b/packages/app/src/utils/rand.ts @@ -0,0 +1,5 @@ +export const getRandomIntInRange = (min: number, max: number): number => { + const minInt = Math.ceil(min); + const maxInt = Math.floor(max); + return Math.floor(Math.random() * (maxInt - minInt) + minInt); +}; diff --git a/packages/app/src/utils/sleep.ts b/packages/app/src/utils/sleep.ts new file mode 100644 index 00000000000..53d726090e3 --- /dev/null +++ b/packages/app/src/utils/sleep.ts @@ -0,0 +1 @@ +export const sleep = (msec: number): Promise => new Promise(resolve => setTimeout(resolve, msec)); diff --git a/yarn.lock b/yarn.lock index 01487c8273a..ef6232355cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15954,6 +15954,13 @@ nocache@^3.0.1: resolved "https://registry.yarnpkg.com/nocache/-/nocache-3.0.1.tgz#54d8b53a7e0a0aa1a288cfceab8a3cefbcde67d4" integrity sha512-Gh39xwJwBKy0OvFmWfBs/vDO4Nl7JhnJtkqNP76OUinQz7BiMoszHYrIDHHAaqVl/QKVxCEy4ZxC/XZninu7nQ== +node-cron@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/node-cron/-/node-cron-3.0.2.tgz#bb0681342bd2dfb568f28e464031280e7f06bd01" + integrity sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ== + dependencies: + uuid "8.3.2" + node-emoji@^1.11.0: version "1.11.0" resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c"