1
0
mirror of https://github.com/tormachris/cf-workers-status-page.git synced 2024-09-21 05:03:02 +02:00

chore(perf): save only failed days to KV storage

This commit is contained in:
Adam Janis 2020-11-12 18:57:42 +01:00
parent c3af9db11a
commit 541bdace4b
6 changed files with 88 additions and 89 deletions

View File

@ -1,6 +1,7 @@
settings: settings:
title: "Status Page" title: "Status Page"
logo: logo-192x192.png url: "https://status-page.eidam.dev" # for Slack messages
logo: logo-192x192.png # image in ./public/ folder
daysInHistogram: 90 daysInHistogram: 90
allmonitorsOperational: "All Systems Operational" allmonitorsOperational: "All Systems Operational"
@ -8,7 +9,9 @@ settings:
monitorLabelOperational: "Operational" monitorLabelOperational: "Operational"
monitorLabelNotOperational: "Not great not terrible" monitorLabelNotOperational: "Not great not terrible"
monitorLabelNoData: "No data" monitorLabelNoData: "No data"
dayInHistogramNoData: "No data"
dayInHistogramOperational: "All good"
dayInHistogramNotOperational: "Some checks failed"
monitors: monitors:
- id: kiwi-com-homepage - id: kiwi-com-homepage
@ -71,13 +74,6 @@ monitors:
method: GET method: GET
expectStatus: 403 expectStatus: 403
- id: google-com-2
name: Google.com
description: Google homepage
url: 'https://www.google.com'
method: GET
expectStatus: 200
- id: cf-workers-status-page-2 - id: cf-workers-status-page-2
name: This Workers Status Page project made public name: This Workers Status Page project made public
description: /shrug description: /shrug
@ -114,13 +110,6 @@ monitors:
method: GET method: GET
expectStatus: 403 expectStatus: 403
- id: google-com-22
name: Google.com
description: Google homepage
url: 'https://www.google.com'
method: GET
expectStatus: 200
- id: cf-workers-status-page-22 - id: cf-workers-status-page-22
name: This Workers Status Page project made public name: This Workers Status Page project made public
description: /shrug description: /shrug
@ -146,7 +135,7 @@ monitors:
name: Hello World name: Hello World
url: 'http://cnn.cn/' url: 'http://cnn.cn/'
method: GET method: GET
expectStatus: 200 expectStatus: 201
- id: eidam-dev-333 - id: eidam-dev-333
@ -156,13 +145,6 @@ monitors:
method: GET method: GET
expectStatus: 403 expectStatus: 403
- id: google-com-333
name: Google.com
description: Google homepage
url: 'https://www.google.com'
method: GET
expectStatus: 200
- id: cf-workers-status-page-333 - id: cf-workers-status-page-333
name: This Workers Status Page project made public name: This Workers Status Page project made public
description: /shrug description: /shrug
@ -206,13 +188,6 @@ monitors:
method: GET method: GET
expectStatus: 403 expectStatus: 403
- id: 25-google-com
name: Bing.com
description: Bing homepage
url: 'https://www.google.com'
method: GET
expectStatus: 200
- id: 25-cf-workers-status-page - id: 25-cf-workers-status-page
name: This Workers Status Page project made public name: This Workers Status Page project made public
description: /shrug description: /shrug
@ -251,12 +226,6 @@ monitors:
method: GET method: GET
expectStatus: 403 expectStatus: 403
- id: 25-google-com-2
name: Google.com
description: Google homepage
url: 'https://www.google.com'
method: GET
expectStatus: 200
- id: 25-cf-workers-status-page-2 - id: 25-cf-workers-status-page-2
name: This Workers Status Page project made public name: This Workers Status Page project made public
@ -294,13 +263,6 @@ monitors:
method: GET method: GET
expectStatus: 403 expectStatus: 403
- id: 25-google-com-22
name: Google.com
description: Google homepage
url: 'https://www.google.com'
method: GET
expectStatus: 200
- id: 25-cf-workers-status-page-22 - id: 25-cf-workers-status-page-22
name: This Workers Status Page project made public name: This Workers Status Page project made public
description: /shrug description: /shrug
@ -336,12 +298,6 @@ monitors:
method: GET method: GET
expectStatus: 403 expectStatus: 403
- id: 25-google-com-333
name: Google.com
description: Google homepage
url: 'https://www.google.com'
method: GET
expectStatus: 200
- id: 25-cf-workers-status-page-333 - id: 25-cf-workers-status-page-333
name: This Workers Status Page project made public name: This Workers Status Page project made public

View File

@ -24,6 +24,8 @@ export async function getEdgeProps() {
if (x.metadata.operational === false) monitorsOperational = false if (x.metadata.operational === false) monitorsOperational = false
}) })
console.log(JSON.stringify(kvMonitorsMap))
// transform KV list to array of failed days // transform KV list to array of failed days
const kvMonitorsFailedDaysArray = kvMonitorsFailedDays.map(x => { const kvMonitorsFailedDaysArray = kvMonitorsFailedDays.map(x => {
return x.name return x.name
@ -79,9 +81,13 @@ export default function Index({
? config.settings.allmonitorsOperational ? config.settings.allmonitorsOperational
: config.settings.notAllmonitorsOperational} : config.settings.notAllmonitorsOperational}
</div> </div>
<div className="black-text"> {typeof window !== 'undefined' ? (
checked {Math.round((Date.now() - kvLastUpdate) / 1000)} sec ago <div className="black-text">
</div> checked {Math.round((Date.now() - kvLastUpdate) / 1000)} sec ago
</div>
) : (
''
)}
</div> </div>
</div> </div>
{config.monitors.map((monitor, key) => { {config.monitors.map((monitor, key) => {

View File

@ -15,22 +15,22 @@ export default function MonitorHistogram({
key={`${monitor.id}-histogram`} key={`${monitor.id}-histogram`}
className="horizontal flex histogram" className="horizontal flex histogram"
> >
{Array.from(Array(config.settings.daysInHistogram + 1).keys()).map(key => { {Array.from(Array(config.settings.daysInHistogram).keys()).map(key => {
date.setDate(date.getDate() + 1) date.setDate(date.getDate() + 1)
const dayInHistory = date.toISOString().split('T')[0] const dayInHistogram = date.toISOString().split('T')[0]
const dayInHistoryKey = 'h_' + monitor.id + '_' + dayInHistory const dayInHistogramKey = 'h_' + monitor.id + '_' + dayInHistogram
let bg = '' let bg = ''
let dayInHistoryStatus = 'No data' let dayInHistogramLabel = config.settings.dayInHistogramNoData
// filter all dates before first check, check the rest // filter all dates before first check, check the rest
if (kvMonitor && kvMonitor.firstCheck <= dayInHistory) { if (kvMonitor && kvMonitor.firstCheck <= dayInHistogram) {
if (!kvMonitorsFailedDaysArray.includes(dayInHistoryKey)) { if (!kvMonitorsFailedDaysArray.includes(dayInHistogramKey)) {
bg = 'green' bg = 'green'
dayInHistoryStatus = 'No outage recorded' dayInHistogramLabel = config.settings.dayInHistogramOperational
} else { } else {
bg = 'orange' bg = 'orange'
dayInHistoryStatus = 'Some outages' dayInHistogramLabel = config.settings.dayInHistogramNotOperational
} }
} }
@ -38,7 +38,7 @@ export default function MonitorHistogram({
<div key={key} className="hitbox"> <div key={key} className="hitbox">
<div <div
className={`${bg} bar`} className={`${bg} bar`}
data-tooltip={`${dayInHistory} - ${dayInHistoryStatus}`} data-tooltip={`${dayInHistogram} - ${dayInHistogramLabel}`}
/> />
</div> </div>
) )

View File

@ -1,3 +1,5 @@
import config from '../../config.yaml'
export default function MonitorStatusLabel({ kvMonitorsMap, monitor }) { export default function MonitorStatusLabel({ kvMonitorsMap, monitor }) {
let labelColor = 'grey' let labelColor = 'grey'
let labelText = 'No data' let labelText = 'No data'
@ -5,10 +7,10 @@ export default function MonitorStatusLabel({ kvMonitorsMap, monitor }) {
if (typeof kvMonitorsMap[monitor.id] !== 'undefined') { if (typeof kvMonitorsMap[monitor.id] !== 'undefined') {
if (kvMonitorsMap[monitor.id].operational) { if (kvMonitorsMap[monitor.id].operational) {
labelColor = 'green' labelColor = 'green'
labelText = 'Operational' labelText = config.settings.monitorLabelOperational
} else { } else {
labelColor = 'orange' labelColor = 'orange'
labelText = 'Not great not terrible' labelText = config.settings.monitorLabelNotOperational
} }
} }

View File

@ -1,6 +1,12 @@
import config from '../../config.yaml' import config from '../../config.yaml'
import { setKV, getKVWithMetadata, gcMonitors, getKV } from './helpers' import {
setKV,
getKVWithMetadata,
gcMonitors,
getKV,
notifySlack,
} from './helpers'
function getDate() { function getDate() {
return new Date().toISOString().split('T')[0] return new Date().toISOString().split('T')[0]
@ -14,7 +20,7 @@ export async function processCronTrigger(event) {
method: monitor.method || 'GET', method: monitor.method || 'GET',
redirect: monitor.followRedirect ? 'follow' : 'manual', redirect: monitor.followRedirect ? 'follow' : 'manual',
headers: { headers: {
'User-Agent': 'cf-worker-status-page', 'User-Agent': config.settings.user_agent || 'cf-worker-status-page',
}, },
} }
@ -28,29 +34,32 @@ export async function processCronTrigger(event) {
firstCheck: kvState.metadata ? kvState.metadata.firstCheck : getDate(), firstCheck: kvState.metadata ? kvState.metadata.firstCheck : getDate(),
} }
// Write current status if status changed or for first time // write current status if status changed or for first time
if ( if (
!kvState.metadata || !kvState.metadata ||
kvState.metadata.operational !== newMetadata.operational kvState.metadata.operational !== newMetadata.operational
) { ) {
console.log('Saving changed state..') console.log('Saving changed state..')
await setKV('s_' + monitor.id, null, newMetadata) // first try to notify Slack in case fetch() or other limit is reached
if (typeof SECRET_SLACK_WEBHOOK_URL !== 'undefined') {
if (typeof SECRET_SLACK_WEBHOOK !== 'undefined') {
await notifySlack(monitor, newMetadata) await notifySlack(monitor, newMetadata)
} }
if (!newMetadata.operational) { await setKV('s_' + monitor.id, null, newMetadata)
// 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 // write daily status if monitor is not operational
if (!kvFailedDayStatus) { if (!newMetadata.operational) {
console.log('Saving new failed daily status..') // try to get failed daily status first as KV read is cheaper than write
await setKV(kvFailedDayStatusKey, null) const kvFailedDayStatusKey = 'h_' + monitor.id + '_' + getDate()
} console.log(kvFailedDayStatusKey)
const kvFailedDayStatus = await getKV(kvFailedDayStatusKey)
// write if not found
if (!kvFailedDayStatus) {
console.log('Saving new failed daily status..')
await setKV(kvFailedDayStatusKey, null)
} }
} }

View File

@ -1,3 +1,5 @@
import config from '../../config.yaml'
export async function getMonitors() { export async function getMonitors() {
const monitors = await listKV('s_') const monitors = await listKV('s_')
return monitors.keys return monitors.keys
@ -73,18 +75,42 @@ export async function gcMonitors(config) {
}) })
} }
async function notifySlack(monitor, metadata) { export async function notifySlack(monitor, newMetadata) {
const blocks = [ const payload = {
{ attachments: [
type: 'section', {
text: { color: newMetadata.operational ? '#36a64f' : '#f2c744',
type: 'mrkdwn', blocks: [
text: `Some monitor is now in :this: status`, {
type: 'section',
text: {
type: 'mrkdwn',
text: `Monitor *${monitor.name}* changed status to *${
newMetadata.operational
? config.settings.monitorLabelOperational
: config.settings.monitorLabelNotOperational
}*`,
},
},
{
type: 'context',
elements: [
{
type: 'mrkdwn',
text: `${
newMetadata.operational ? ':white_check_mark:' : ':x:'
} \`${monitor.method} ${monitor.url}\` - :eyes: <${
config.settings.url
}|Status Page>`,
},
],
},
],
}, },
}, ],
] }
return fetch(SECRET_SLACK_WEBHOOK_URL, { return fetch(SECRET_SLACK_WEBHOOK_URL, {
body: JSON.stringify({ blocks }), body: JSON.stringify(payload),
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
}) })