Skip to content

Instantly share code, notes, and snippets.

@soyart
Last active June 23, 2022 16:20
Show Gist options
  • Select an option

  • Save soyart/a703f8236c7cae7fc2fcc8ba391c399a to your computer and use it in GitHub Desktop.

Select an option

Save soyart/a703f8236c7cae7fc2fcc8ba391c399a to your computer and use it in GitHub Desktop.
Code for practicing alerting
package main
import (
"crypto/rand"
"fmt"
"math/big"
"strings"
"time"
)
type alert struct {
Level int `json:"level"` // Severity level
SameLevel bool `json:"SameLevel"` // If the alert severity level is unchanged from the previous alert
Text string `json:"text"` // Severity text
Interval int `json:"interval"` // Alert interval
Timer <-chan time.Time `json:"timer"` // Timer to trigger actual alerts
Balance *big.Int `json:"balance"`
}
func main() {
// loop and loopMock creates alerts and decides their severity
// loop()
loopMock()
}
// handleAlert decides when and how to alert
func handleAlert(
i int, prevTimer <-chan time.Time, prevQuit chan struct{}, prevAlert alert, mostRecent alert,
) (
retTimer <-chan time.Time, retQuit chan struct{}, retAlert alert,
) {
alertFunc, thisTimer, thisQuit := newAlertFunc(i, mostRecent.Interval)
retAlert = mostRecent
retQuit = thisQuit
var shouldAlertNow bool
if i == 0 {
// [nil a'] ... (1st alert must always alert now
shouldAlertNow = true
// No one needs 1st run's timer and quit channels
mostRecent.Timer = nil
retTimer = thisTimer
retQuit = nil
} else if mostRecent.SameLevel && prevAlert.SameLevel {
// a a a a [a a'] ... -> wait to alert later on prevTimer
mostRecent.Timer = prevTimer
retTimer = prevTimer
} else if mostRecent.SameLevel && !prevAlert.SameLevel {
// a a a a [b b'] ... -> wait to alert later on thisTimer
mostRecent.Timer = prevTimer
retTimer = prevTimer
} else if !mostRecent.SameLevel && !prevAlert.SameLevel {
// a a a a [b a'] -> alert now!
shouldAlertNow = true
mostRecent.Timer = nil
retTimer = thisTimer
} else if !mostRecent.SameLevel {
// a a a a [b a'] ... -> alert now!
shouldAlertNow = true
mostRecent.Timer = nil
retTimer = thisTimer
}
go alertFunc(mostRecent, shouldAlertNow)
if prevQuit != nil {
close(prevQuit)
}
return retTimer, retQuit, retAlert
}
// newAlertFunc returns a function closed with quit channel.
// This returned function is used to actually alert (print)
func newAlertFunc(funcId int, interval int) (func(alert, bool), <-chan time.Time, chan struct{}) {
// quit will be captured into the returned closure
quit := make(chan struct{})
return func(mostRecent alert, alertNow bool) {
printAlert := func(s string) {
fmt.Printf(
"\n[LoopSendAlerts %d]\tALERT (%s) %+v,\t%v\n\n",
funcId, s, mostRecent, strings.Split(time.Now().String(), " ")[1],
)
}
if alertNow {
printAlert("alertNow")
return
}
// Sends an alert and waits
// select clause blocks here until it breaks
select {
case <-quit:
fmt.Printf("[LoopSendAlerts %d] baling out (%s again): recevied QUIT signal,\n", funcId, mostRecent.Text)
break
// Newer alerts has come
case <-mostRecent.Timer:
printAlert("onTimer")
break
}
}, time.After(time.Second * time.Duration(interval)), quit
}
func loop() {
var c int // counts instance
var prevTimer <-chan time.Time
var prevQuit chan struct{} // nil now or if closed
var prevAlert alert
for {
c++
if c >= 50 {
break
}
balance, err := rand.Int(rand.Reader, big.NewInt(150))
if err != nil {
panic(err.Error())
}
var mostRecent alert
if cmp := balance.Cmp(tresholdx2); cmp > 0 {
mostRecent = l1
} else if cmp := balance.Cmp(treshold); cmp > 0 {
mostRecent = l2
} else if cmp <= 0 {
if balance.Cmp(big.NewInt(0)) == 0 {
// catastrophe
mostRecent = l4
} else {
// critical
mostRecent = l3
}
}
mostRecent.Balance = balance
if mostRecent.Level == prevAlert.Level {
mostRecent.SameLevel = true
}
fmt.Printf(
"[LoopGetBalances %d]\tseverity: %s level: %d balance: %v interval: %d\n",
c, mostRecent.Text, mostRecent.Level, mostRecent.Balance, mostRecent.Interval,
)
prevTimer, prevQuit, prevAlert = handleAlert(c, prevTimer, prevQuit, prevAlert, mostRecent)
time.Sleep(time.Millisecond * time.Duration(fetchInterval))
}
}
func loopMock() {
var prevTimer <-chan time.Time
var prevQuit chan struct{} // nil now or if closed
var prevAlert alert
for i, mostRecent := range mockAlerts {
if mostRecent.Level == prevAlert.Level {
mostRecent.SameLevel = true
}
fmt.Printf(
"[LoopGetBalances %d]\tseverity: %s level: %d balance: %v interval: %d\n",
i, mostRecent.Text, mostRecent.Level, mostRecent.Balance, mostRecent.Interval,
)
prevTimer, prevQuit, prevAlert = handleAlert(i, prevTimer, prevQuit, prevAlert, mostRecent)
time.Sleep(time.Millisecond * time.Duration(fetchInterval))
}
}
var (
fetchInterval = 1250
l1 = alert{Level: 1, Interval: 20, Text: "SAFE", Balance: big.NewInt(10)}
l2 = alert{Level: 2, Interval: 15, Text: "WARN", Balance: big.NewInt(20)}
l3 = alert{Level: 3, Interval: 10, Text: "CRITICAL", Balance: big.NewInt(30)}
l4 = alert{Level: 4, Interval: 5, Text: "CATASTROPHE", Balance: big.NewInt(40)}
mockAlerts = []alert{l1, l1, l1, l1, l1, l1, l1, l1, l1, l1, l1, l1, l1, l1, l1, l1, l1, l1, l2, l2, l2, l3, l3, l3, l2, l2, l3, l3, l3, l4, l4, l4, l4}
// mockAlerts = []alert{l4, l4, l4, l4, l4, l4}
treshold = big.NewInt(25)
tresholdx2 = new(big.Int).Mul(treshold, big.NewInt(2))
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment