Loading histogram ...
diff --git a/src/components/monitorStatusHeader.js b/src/components/monitorStatusHeader.js
index b3b98d35e..8cfd783e3 100644
--- a/src/components/monitorStatusHeader.js
+++ b/src/components/monitorStatusHeader.js
@@ -1,17 +1,15 @@
import config from '../../config.yaml'
-export default function MonitorStatusHeader({ operational, lastUpdate }) {
+export default function MonitorStatusHeader({kvMonitorsMetadata}) {
let backgroundColor = 'green'
let headerText = config.settings.allmonitorsOperational
let textColor = 'black'
- if (!operational) {
+ if (!kvMonitorsMetadata.monitorsOperational) {
backgroundColor = 'yellow'
headerText = config.settings.notAllmonitorsOperational
}
- const lastCheckAgo = Math.round((Date.now() - lastUpdate.value) / 1000)
-
return (
@@ -19,9 +17,9 @@ export default function MonitorStatusHeader({ operational, lastUpdate }) {
{headerText}
{
- lastUpdate.metadata && typeof window !== 'undefined' && (
+ kvMonitorsMetadata.lastUpdate && typeof window !== 'undefined' && (
- checked {lastCheckAgo} sec ago (from {lastUpdate.metadata.loc})
+ checked {Math.round((Date.now() - kvMonitorsMetadata.lastUpdate.time) / 1000)} sec ago (from {kvMonitorsMetadata.lastUpdate.loc})
)
}
diff --git a/src/components/monitorStatusLabel.js b/src/components/monitorStatusLabel.js
index 6a976eb21..0c9517572 100644
--- a/src/components/monitorStatusLabel.js
+++ b/src/components/monitorStatusLabel.js
@@ -1,11 +1,11 @@
import config from '../../config.yaml'
-export default function MonitorStatusLabel({ kvMonitorsMap, monitor }) {
+export default function MonitorStatusLabel({ kvMonitor }) {
let labelColor = 'grey'
let labelText = 'No data'
- if (typeof kvMonitorsMap[monitor.id] !== 'undefined') {
- if (kvMonitorsMap[monitor.id].operational) {
+ if (typeof kvMonitor !== 'undefined') {
+ if (kvMonitor.operational) {
labelColor = 'green'
labelText = config.settings.monitorLabelOperational
} else {
diff --git a/src/functions/cronTrigger.js b/src/functions/cronTrigger.js
index 0aadc3607..2676ac2e3 100644
--- a/src/functions/cronTrigger.js
+++ b/src/functions/cronTrigger.js
@@ -3,7 +3,6 @@ import config from '../../config.yaml'
import {
setKV,
getKVWithMetadata,
- getKV,
notifySlack,
} from './helpers'
@@ -12,9 +11,29 @@ function getDate() {
}
export async function processCronTrigger(event) {
+ // Get monitors state from KV
+ let {value: monitorsState, metadata: monitorsStateMetadata} = await getKVWithMetadata('monitors_data', 'json')
+
+ // Create empty state objects if not exists in KV storage yet
+ if (!monitorsState) {
+ monitorsState = {}
+ }
+ if (!monitorsStateMetadata) {
+ monitorsStateMetadata = {}
+ }
+
+ // Reset default all monitors state to true
+ monitorsStateMetadata.monitorsOperational = true
+
for (const monitor of config.monitors) {
+ // Create default monitor state if does not exist yet
+ if (typeof monitorsState[monitor.id] === 'undefined') {
+ monitorsState[monitor.id] = {failedDays: []}
+ }
+
console.log(`Checking ${monitor.name} ...`)
+ // Fetch the monitors URL
const init = {
method: monitor.method || 'GET',
redirect: monitor.followRedirect ? 'follow' : 'manual',
@@ -24,50 +43,40 @@ export async function processCronTrigger(event) {
}
const checkResponse = await fetch(monitor.url, init)
- const kvState = await getKVWithMetadata('s_' + monitor.id)
+ const monitorOperational = checkResponse.status === (monitor.expectStatus || 200)
- // metadata from monitor settings
- const newMetadata = {
- operational: checkResponse.status === (monitor.expectStatus || 200),
- id: monitor.id,
- firstCheck: kvState.metadata ? kvState.metadata.firstCheck : getDate(),
+ // Send Slack message on monitor change
+ if (monitorsState[monitor.id].operational !== monitorOperational && typeof SECRET_SLACK_WEBHOOK_URL !== 'undefined' && SECRET_SLACK_WEBHOOK_URL !== 'default-gh-action-secret') {
+ event.waitUntil(notifySlack(monitor, monitorOperational))
}
- // write current status if status changed or for first time
- if (
- !kvState.metadata ||
- kvState.metadata.operational !== newMetadata.operational
- ) {
- console.log('Saving changed state..')
+ monitorsState[monitor.id].operational = checkResponse.status === (monitor.expectStatus || 200)
+ monitorsState[monitor.id].firstCheck = monitorsState[monitor.id].firstCheck || getDate()
- // first try to notify Slack in case fetch() or other limit is reached
- if (typeof SECRET_SLACK_WEBHOOK_URL !== 'undefined' && SECRET_SLACK_WEBHOOK_URL !== 'default-gh-action-secret') {
- await notifySlack(monitor, newMetadata)
- }
-
- await setKV('s_' + monitor.id, null, newMetadata)
- }
+ // Set monitorsOperational and push current day to failedDays
+ if (!monitorOperational) {
+ monitorsStateMetadata.monitorsOperational = false
- // write daily status if monitor is not operational
- if (!newMetadata.operational) {
- // try to get failed daily status first as KV read is cheaper than write
- const kvFailedDayStatusKey = 'h_' + monitor.id + '_' + getDate()
- const kvFailedDayStatus = await getKV(kvFailedDayStatusKey)
-
- // write if not found
- if (!kvFailedDayStatus) {
- console.log('Saving new failed daily status..')
- await setKV(kvFailedDayStatusKey, null)
+ const failedDay = getDate()
+ if (!monitorsState[monitor.id].failedDays.includes(failedDay)) {
+ console.log('Saving new failed daily status ...')
+ monitorsState[monitor.id].failedDays.push(failedDay)
}
}
}
- // save last check timestamp including PoP location
+ // Get Worker PoP and save it to monitorsStateMetadata
const res = await fetch('https://cloudflare-dns.com/dns-query', {
method: 'OPTIONS',
})
const loc = res.headers.get('cf-ray').split('-')[1]
- await setKV('lastUpdate', Date.now(), { loc })
+ monitorsStateMetadata.lastUpdate = {
+ loc,
+ time: Date.now()
+ }
+
+ // Save monitorsState and monitorsStateMetadata to KV storage
+ await setKV('monitors_data', JSON.stringify(monitorsState), monitorsStateMetadata)
return new Response('OK')
}
diff --git a/src/functions/helpers.js b/src/functions/helpers.js
index 7df2a20b4..0853b1c13 100644
--- a/src/functions/helpers.js
+++ b/src/functions/helpers.js
@@ -2,72 +2,29 @@ import config from '../../config.yaml'
import {useEffect, useState} from 'react'
export async function getMonitors() {
- const monitors = await listKV('s_')
- return monitors.keys
-}
-
-export async function getMonitorsHistory() {
- const monitorsHistory = await listKV('h_', 300)
- return monitorsHistory.keys
-}
-
-export async function getLastUpdate() {
- return await getKVWithMetadata('lastUpdate')
-}
-
-export async function listKV(prefix = '', cacheTtl = false) {
- const cacheKey = 'list_' + prefix + '_' + process.env.BUILD_ID
-
- if (cacheTtl) {
- const cachedResponse = await getKV(cacheKey)
- if (cachedResponse) {
- return JSON.parse(cachedResponse)
- }
- }
-
- let list = []
- let cursor = null
- let res = {}
- do {
- res = await KV_STATUS_PAGE.list({ prefix: prefix, cursor })
- list = list.concat(res.keys)
- cursor = res.cursor
- } while (!res.list_complete)
-
- if (cacheTtl) {
- await setKV(cacheKey, JSON.stringify({ keys: list }), null, cacheTtl)
- }
- return { keys: list }
+ return await getKVWithMetadata('monitors_data', "json")
}
export async function setKV(key, value, metadata, expirationTtl) {
return KV_STATUS_PAGE.put(key, value, { metadata, expirationTtl })
}
-export async function getKV(key, type = 'text') {
- return KV_STATUS_PAGE.get(key, type)
-}
-
-export async function getKVWithMetadata(key) {
- return KV_STATUS_PAGE.getWithMetadata(key)
-}
-
-export async function deleteKV(key) {
- return KV_STATUS_PAGE.delete(key)
+export async function getKVWithMetadata(key, type = 'text') {
+ return KV_STATUS_PAGE.getWithMetadata(key, type)
}
-export async function notifySlack(monitor, newMetadata) {
+export async function notifySlack(monitor, operational) {
const payload = {
attachments: [
{
- color: newMetadata.operational ? '#36a64f' : '#f2c744',
+ color: operational ? '#36a64f' : '#f2c744',
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `Monitor *${monitor.name}* changed status to *${
- newMetadata.operational
+ operational
? config.settings.monitorLabelOperational
: config.settings.monitorLabelNotOperational
}*`,
@@ -79,7 +36,7 @@ export async function notifySlack(monitor, newMetadata) {
{
type: 'mrkdwn',
text: `${
- newMetadata.operational ? ':white_check_mark:' : ':x:'
+ operational ? ':white_check_mark:' : ':x:'
} \`${monitor.method ? monitor.method : "GET"} ${monitor.url}\` - :eyes: <${
config.settings.url
}|Status Page>`,