Repository: elastic/synthetics
Pull request #932 (2024-06-11 08:54:19)

feat: support every 10 and 30 seconds intervals for lightweight monitors
fixes https://github.com/elastic/synthetics/issues/930
support 10 and s30 seconds intervals for lightweight monitors !!

Some changes were also needed in kibana https://github.com/elastic/kibana/pull/185920

shahzad31: > Thanks @shahzad31 Code looks good. Few thoughts.
> 
> * What happens if users push these changes to an older version of Kibana? Does the API reject the monitors?
> * Can we add a follow up doc issue and add the relevant info for Lightweight and Browser monitor and also suggest from what stack we start supporting these new schedules.

Usage against old kibana will throw an error, since we do validation there.

Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d99ead6..49f5f79 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -55,9 +55,7 @@ jobs:
         run: npm dist-tag --otp=${TOTP_CODE} add "${NPM_PACKAGE}@${VERSION}" stack_release
 
       - if: ${{ always() && github.event.inputs.dry-run == 'false' }}
-        uses: elastic/apm-pipeline-library/.github/actions/notify-build-status@current
+        uses: elastic/oblt-actions/slack/notify-result@v1
         with:
-          vaultUrl: ${{ secrets.VAULT_ADDR }}
-          vaultRoleId: ${{ secrets.VAULT_ROLE_ID }}
-          vaultSecretId: ${{ secrets.VAULT_SECRET_ID }}
-          slackChannel: "#synthetics-user_experience-uptime"
+          bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+          channel-id: "#synthetics-user_experience-uptime"
diff --git a/src/dsl/monitor.ts b/src/dsl/monitor.ts
index e007153..fdcf098 100644
--- a/src/dsl/monitor.ts
+++ b/src/dsl/monitor.ts
@@ -41,7 +41,7 @@ export const SyntheticsLocations = Object.keys(
   LocationsMap
 ) as SyntheticsLocationsType[];
 export const ALLOWED_SCHEDULES = [
-  1, 3, 5, 10, 15, 20, 30, 60, 120, 240,
+  1, 2, 3, 5, 10, 15, 20, 30, 60, 120, 240,
 ] as const;
 
 export interface AlertConfig {
diff --git a/src/push/monitor.ts b/src/push/monitor.ts
index b7982c7..80996ea 100644
--- a/src/push/monitor.ts
+++ b/src/push/monitor.ts
@@ -271,7 +271,8 @@ export function buildMonitorFromYaml(
     ...normalizeConfig(config),
     retestOnFailure,
     privateLocations,
-    schedule: schedule || options.schedule,
+    schedule:
+      (schedule as typeof ALLOWED_SCHEDULES[number]) || options.schedule,
     alert: alertConfig,
   });
 
@@ -285,7 +286,7 @@ export function buildMonitorFromYaml(
   return mon;
 }
 
-// Deletes unncessary fields from the lightweight monitor config
+// Deletes unnecessary fields from the lightweight monitor config
 //  that is not supported by the Kibana API
 function normalizeConfig(config: MonitorConfig) {
   delete config['private_locations'];
@@ -354,6 +355,7 @@ export function parseSchedule(schedule: string) {
   // split between non-digit (\D) and a digit (\d)
   const durations = duration.split(/(?<=\D)(?=\d)/g);
   let minutes = 0;
+  let seconds = 0;
   for (const dur of durations) {
     // split between a digit and non-digit
     const [value, format] = dur.split(/(?<=\d)(?=\D)/g);
@@ -361,7 +363,11 @@ export function parseSchedule(schedule: string) {
     const scheduleValue = parseInt(value, 10);
     switch (format) {
       case 's':
-        minutes += Math.round(scheduleValue / 60);
+        if (scheduleValue < 60) {
+          seconds += scheduleValue;
+        } else {
+          minutes += Math.round(scheduleValue / 60);
+        }
         break;
       case 'm':
         minutes += scheduleValue;
@@ -374,12 +380,16 @@ export function parseSchedule(schedule: string) {
         break;
     }
   }
-  return nearestSchedule(minutes);
+  return nearestSchedule(minutes, seconds);
 }
 
 // Find the nearest schedule that is supported by the platform
 // from the parsed schedule value
-function nearestSchedule(minutes) {
+function nearestSchedule(minutes: number, seconds: number) {
+  if (seconds > 0 && minutes === 0) {
+    // we allow only 10 and 30 seconds, return the nearest one
+    return seconds < 20 ? '10s' : '30s';
+  }
   let nearest: typeof ALLOWED_SCHEDULES[number] = ALLOWED_SCHEDULES[0];
   let prev = Math.abs(nearest - minutes);
   for (let i = 1; i < ALLOWED_SCHEDULES.length; i++) {


Test patch:
diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index 9c650f5..eb24717 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -38,9 +38,7 @@ jobs:
           path: "**/junit_*.xml"
           if-no-files-found: error
       - if: always()
-        uses: elastic/apm-pipeline-library/.github/actions/notify-build-status@current
+        uses: elastic/oblt-actions/slack/notify-result@v1
         with:
-          vaultUrl: ${{ secrets.VAULT_ADDR }}
-          vaultRoleId: ${{ secrets.VAULT_ROLE_ID }}
-          vaultSecretId: ${{ secrets.VAULT_SECRET_ID }}
-          slackChannel: "#synthetics-notify"
+          bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+          channel-id: "#synthetics-notify"
diff --git a/__tests__/push/__snapshots__/index.test.ts.snap b/__tests__/push/__snapshots__/index.test.ts.snap
index 1ec22f7..82e93d0 100644
--- a/__tests__/push/__snapshots__/index.test.ts.snap
+++ b/__tests__/push/__snapshots__/index.test.ts.snap
@@ -25,7 +25,7 @@ Run 'npx @elastic/synthetics init' to create project with default settings.
 exports[`Push error on invalid schedule 1`] = `
 "Aborted. Invalid synthetics project settings.
 
-Set default schedule(12) to one of the allowed values - 1,3,5,10,15,20,30,60,120,240
+Set default schedule(12) to one of the allowed values - 1,2,3,5,10,15,20,30,60,120,240
 
 Run 'npx @elastic/synthetics init' to create project with default settings.
 "
diff --git a/__tests__/push/monitor.test.ts b/__tests__/push/monitor.test.ts
index 34bd1f5..0c0fe9b 100644
--- a/__tests__/push/monitor.test.ts
+++ b/__tests__/push/monitor.test.ts
@@ -112,13 +112,14 @@ describe('Monitors', () => {
     expect(() => parseSchedule('* * * *')).toThrowError(
       `Monitor schedule format(* * * *) not supported: use '@every' syntax instead`
     );
-    expect(parseSchedule('@every 4s')).toBe(1);
+    expect(parseSchedule('@every 4s')).toBe('10s');
+    expect(parseSchedule('@every 40s')).toBe('30s');
     expect(parseSchedule('@every 70s')).toBe(1);
-    expect(parseSchedule('@every 121s')).toBe(3);
+    expect(parseSchedule('@every 121s')).toBe(2);
     expect(parseSchedule('@every 1m')).toBe(1);
-    expect(parseSchedule('@every 2m30s')).toBe(3);
+    expect(parseSchedule('@every 2m30s')).toBe(2);
     expect(parseSchedule('@every 181s')).toBe(3);
-    expect(parseSchedule('@every 2m10s')).toBe(3);
+    expect(parseSchedule('@every 2m10s')).toBe(2);
     expect(parseSchedule('@every 4m25s')).toBe(5);
     expect(parseSchedule('@every 16m')).toBe(15);
     expect(parseSchedule('@every 24m')).toBe(20);