From 62cff6efdf9ce0b741b1c6b51c8811fe32a26c78 Mon Sep 17 00:00:00 2001 From: Ying Date: Fri, 11 Jul 2025 14:32:02 -0400 Subject: [PATCH 1/2] Calculating next run using dtstart if in the future --- .../common/scheduled/scheduled_query.test.ts | 76 +++++++++++++++++++ .../common/scheduled/scheduled_query.ts | 22 +++++- 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.test.ts b/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.test.ts index a999c43311e7a..f6fd06509cb0b 100644 --- a/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.test.ts +++ b/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.test.ts @@ -25,6 +25,7 @@ import { transformResponse, scheduledQueryFactory, CreatedAtSearchResponse, + transformSingleResponse, } from './scheduled_query'; import { ReportingCore } from '../../..'; import { ScheduledReportType } from '../../../types'; @@ -1216,6 +1217,81 @@ describe('transformResponse', () => { }); }); + it('should correctly transform a response with rrule.dtstart is in the future', () => { + jest.useFakeTimers(); + jest.setSystemTime(new Date('2025-05-06T21:10:17.137Z')); + + // current time is 2025-05-06T21:10:17.137Z which is a Tuesday + // schedule is set to run every Friday at 17:00 UTC + // start time is set to 2025-05-11T12:00:00.000Z (which is a Sunday) + // next run should be the next Friday after 2025-05-11T12:00:00.000Z which is 2025-05-16T17:00:00.000Z + // not the actual next friday which would be 2025-05-09T17:00:00.000Z + const dtstart = '2025-05-11T12:00:00.000Z'; + expect( + transformSingleResponse(mockLogger, { + type: 'scheduled_report', + id: 'aa8b6fb3-cf61-4903-bce3-eec9ddc823ca', + namespaces: ['a-space'], + attributes: { + createdAt: '2025-05-06T21:10:17.137Z', + createdBy: 'elastic', + enabled: true, + jobType: 'printable_pdf_v2', + meta: { + isDeprecated: false, + layout: 'preserve_layout', + objectType: 'dashboard', + }, + migrationVersion: '9.1.0', + title: '[Logs] Web Traffic', + payload, + schedule: { + rrule: { + dtstart, + freq: 3, + interval: 1, + byhour: [17], + byminute: [0], + byweekday: ['FR'], + tzid: 'UTC', + }, + }, + }, + references: [], + managed: false, + updated_at: '2025-05-06T21:10:17.137Z', + created_at: '2025-05-06T21:10:17.137Z', + version: 'WzEsMV0=', + coreMigrationVersion: '8.8.0', + typeMigrationVersion: '10.1.0', + score: 0, + }) + ).toEqual({ + id: 'aa8b6fb3-cf61-4903-bce3-eec9ddc823ca', + created_at: '2025-05-06T21:10:17.137Z', + created_by: 'elastic', + enabled: true, + jobtype: 'printable_pdf_v2', + next_run: '2025-05-16T17:00:00.000Z', + payload: jsonPayload, + schedule: { + rrule: { + dtstart, + freq: 3, + interval: 1, + byhour: [17], + byminute: [0], + byweekday: ['FR'], + tzid: 'UTC', + }, + }, + space_id: 'a-space', + title: '[Logs] Web Traffic', + }); + + jest.useRealTimers(); + }); + it('handles malformed payload', () => { const malformedSo = { ...savedObjects[0], diff --git a/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.ts b/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.ts index f60aab8776ff1..e6f55c16f7cb2 100644 --- a/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.ts +++ b/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.ts @@ -73,10 +73,24 @@ export function transformSingleResponse( ); const schedule = so.attributes.schedule; - const _rrule = new RRule({ - ...schedule.rrule, - dtstart: new Date(), - }); + + // get start date + let dtstart = new Date(); + const rruleStart = schedule.rrule.dtstart; + if (rruleStart) { + try { + // if start date is provided and in the future, use it, otherwise use current time + const startDateValue = new Date(rruleStart).valueOf(); + if (startDateValue > Date.now()) { + dtstart = new Date(rruleStart); + } + } catch (e) { + logger.debug( + `Failed to parse rrule.dtstart for scheduled report next run calculation - default to now ${id}: ${e.message}` + ); + } + } + const _rrule = new RRule({ ...schedule.rrule, dtstart }); let payload: ReportApiJSON['payload'] | undefined; try { From 1173baab69283f20d444b7948048f0647fd25bad Mon Sep 17 00:00:00 2001 From: Ying Date: Tue, 15 Jul 2025 11:38:16 -0400 Subject: [PATCH 2/2] Fix --- .../server/routes/common/scheduled/scheduled_query.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.ts b/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.ts index e6f55c16f7cb2..05028a1794818 100644 --- a/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.ts +++ b/x-pack/platform/plugins/private/reporting/server/routes/common/scheduled/scheduled_query.ts @@ -81,8 +81,9 @@ export function transformSingleResponse( try { // if start date is provided and in the future, use it, otherwise use current time const startDateValue = new Date(rruleStart).valueOf(); - if (startDateValue > Date.now()) { - dtstart = new Date(rruleStart); + const now = Date.now(); + if (startDateValue > now) { + dtstart = new Date(startDateValue + 60000); // add 1 minute to ensure it's in the future } } catch (e) { logger.debug(