diff --git a/packages/core/admin/ee/server/bootstrap.js b/packages/core/admin/ee/server/bootstrap.js index 678ce883e9..5467f8bc74 100644 --- a/packages/core/admin/ee/server/bootstrap.js +++ b/packages/core/admin/ee/server/bootstrap.js @@ -31,6 +31,8 @@ module.exports = async () => { // Decorate the entity service with review workflow logic const { decorator } = getService('review-workflows-decorator'); strapi.entityService.decorate(decorator); + + await getService('review-workflows-weekly-metrics').registerCron(); } await getService('seat-enforcement').seatEnforcementWorkflow(); diff --git a/packages/core/admin/ee/server/services/index.js b/packages/core/admin/ee/server/services/index.js index 11064d381a..d9f71e1b1b 100644 --- a/packages/core/admin/ee/server/services/index.js +++ b/packages/core/admin/ee/server/services/index.js @@ -12,4 +12,5 @@ module.exports = { 'review-workflows-validation': require('./review-workflows/validation'), 'review-workflows-decorator': require('./review-workflows/entity-service-decorator'), 'review-workflows-metrics': require('./review-workflows/metrics'), + 'review-workflows-weekly-metrics': require('./review-workflows/metrics/weekly-metrics'), }; diff --git a/packages/core/admin/ee/server/services/review-workflows/metrics.js b/packages/core/admin/ee/server/services/review-workflows/metrics/index.js similarity index 64% rename from packages/core/admin/ee/server/services/review-workflows/metrics.js rename to packages/core/admin/ee/server/services/review-workflows/metrics/index.js index d4893e64a1..fe601c5828 100644 --- a/packages/core/admin/ee/server/services/review-workflows/metrics.js +++ b/packages/core/admin/ee/server/services/review-workflows/metrics/index.js @@ -24,6 +24,22 @@ const sendDidEditWorkflow = async () => { strapi.telemetry.send('didEditWorkflow', {}); }; +const sendDidSendReviewWorkflowPropertiesOnceAWeek = async ( + numberOfActiveWorkflows, + avgStagesCount, + maxStagesCount, + activatedContentTypes +) => { + strapi.telemetry.send('didSendReviewWorkflowPropertiesOnceAWeek', { + groupProperties: { + numberOfActiveWorkflows, + avgStagesCount, + maxStagesCount, + activatedContentTypes, + }, + }); +}; + module.exports = { sendDidCreateStage, sendDidEditStage, @@ -31,4 +47,5 @@ module.exports = { sendDidChangeEntryStage, sendDidCreateWorkflow, sendDidEditWorkflow, + sendDidSendReviewWorkflowPropertiesOnceAWeek, }; diff --git a/packages/core/admin/ee/server/services/review-workflows/metrics/weekly-metrics.js b/packages/core/admin/ee/server/services/review-workflows/metrics/weekly-metrics.js new file mode 100644 index 0000000000..fc61df3834 --- /dev/null +++ b/packages/core/admin/ee/server/services/review-workflows/metrics/weekly-metrics.js @@ -0,0 +1,76 @@ +'use strict'; + +const { flow, map, sum, size, mean, max, defaultTo } = require('lodash/fp'); +const { add } = require('date-fns'); +const { getService } = require('../../../../../server/utils'); + +const ONE_WEEK = 7 * 24 * 60 * 60 * 1000; + +const getWeeklyCronScheduleAt = (date) => + `${date.getSeconds()} ${date.getMinutes()} ${date.getHours()} * * ${date.getDay()}`; + +const getMetricsStoreValue = async () => { + const value = await strapi.store.get({ type: 'plugin', name: 'ee', key: 'metrics' }); + return defaultTo({}, value); +}; + +const setMetricsStoreValue = (value) => + strapi.store.set({ type: 'plugin', name: 'ee', key: 'metrics', value }); + +module.exports = ({ strapi }) => { + const metrics = getService('review-workflows-metrics', { strapi }); + const workflowsService = getService('workflows', { strapi }); + + return { + async computeMetrics() { + // There will never be more than 200 workflow, so we can safely fetch them all + const workflows = await workflowsService.find({ populate: 'stages' }); + + const stagesCount = flow( + map('stages'), // Number of stages per workflow + map(size) + )(workflows); + + const contentTypesCount = flow( + map('contentTypes'), // Number of content types per workflow + map(size) + )(workflows); + + return { + numberOfActiveWorkflows: size(workflows), + avgStagesCount: mean(stagesCount), + maxStagesCount: max(stagesCount), + activatedContentTypes: sum(contentTypesCount), + }; + }, + + async sendMetrics() { + const computedMetrics = await this.computeMetrics(); + metrics.sendDidSendReviewWorkflowPropertiesOnceAWeek(computedMetrics); + + const metricsInfoStored = await getMetricsStoreValue(); + await setMetricsStoreValue({ ...metricsInfoStored, lastWeeklyUpdate: new Date().getTime() }); + }, + + async ensureWeeklyStoredCronSchedule() { + const metricsInfoStored = await getMetricsStoreValue(); + const { weeklySchedule: currentSchedule, lastWeeklyUpdate } = metricsInfoStored; + + const now = new Date(); + let weeklySchedule = currentSchedule; + + if (!currentSchedule || !lastWeeklyUpdate || lastWeeklyUpdate + ONE_WEEK < now.getTime()) { + weeklySchedule = getWeeklyCronScheduleAt(add(now, { seconds: 10 })); + await setMetricsStoreValue({ ...metricsInfoStored, weeklySchedule }); + } + + return weeklySchedule; + }, + + async registerCron() { + const weeklySchedule = await this.ensureWeeklyStoredCronSchedule(); + + strapi.cron.add({ [weeklySchedule]: this.sendMetrics.bind(this) }); + }, + }; +}; diff --git a/packages/core/upload/server/services/metrics/weekly-metrics.js b/packages/core/upload/server/services/metrics/weekly-metrics.js index a2074d3cc9..e8ba5fb864 100644 --- a/packages/core/upload/server/services/metrics/weekly-metrics.js +++ b/packages/core/upload/server/services/metrics/weekly-metrics.js @@ -2,8 +2,8 @@ const { defaultTo } = require('lodash/fp'); const { add } = require('date-fns'); -const { FOLDER_MODEL_UID, FILE_MODEL_UID } = require('../../constants'); const { getWeeklyCronScheduleAt } = require('../../utils/cron'); +const { FOLDER_MODEL_UID, FILE_MODEL_UID } = require('../../constants'); const ONE_WEEK = 7 * 24 * 60 * 60 * 1000; diff --git a/packages/core/upload/server/utils/__tests__/cron.test.js b/packages/core/upload/server/utils/__tests__/cron.test.js index dbbd281238..9ef896bcd7 100644 --- a/packages/core/upload/server/utils/__tests__/cron.test.js +++ b/packages/core/upload/server/utils/__tests__/cron.test.js @@ -6,7 +6,6 @@ describe('cron', () => { describe('getWeeklyCronScheduleAt', () => { test('2022-07-22T15:43:40.036 => 40 43 15 * * 5', () => { const date = new Date('2022-07-22T15:43:40.036'); // it's a friday - const result = getWeeklyCronScheduleAt(date); expect(result).toBe('40 43 15 * * 5'); });