From d818e8c15864f226740475e6b3076e79817c08ab Mon Sep 17 00:00:00 2001 From: Ava Affine Date: Sat, 30 Nov 2024 10:49:16 -0800 Subject: [PATCH] Handle interrupts and panics to mitigate data loss This commit introduces a deferred call to a state teardown function This is needed to properly flush data to the backing documentbuffer as well as to truncate its underlying store. In doing so we make sure data loss from process termination is minimal to nil. when ever a panic happens or a signal is thrown the call to Teardown() is made Signed-off-by: Ava Affine --- internal/state/state.go | 20 ++++++++++++++++++++ main.go | 10 ++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/internal/state/state.go b/internal/state/state.go index ab8469b..1325546 100644 --- a/internal/state/state.go +++ b/internal/state/state.go @@ -48,6 +48,7 @@ const ( var eventMutex sync.RWMutex var eventSubscriptionCache = [NumEventTypes][]chan Event{} +var eventStorageFileName string var eventStream docbuf.DocumentBuffer var maxEventsInMemory int @@ -65,10 +66,29 @@ func Init(eventMemCacheSize int, eventStoreFileName string) error { return errors.Join(errors.New(BadEventStreamInit), err) } + eventStorageFileName = eventStoreFileName maxEventsInMemory = eventMemCacheSize return nil } +// return no error. we are handling SIGINT +func Teardown() { + // riskily ignore all locking.... + // we are handling a termination signal after all + i, e := eventStream.Close() + if e != nil { + logging.Warn("failed to close document buffer: %s", e.Error()) + logging.Warn("will attempt to truncate event store anyways") + } + + e = os.Truncate(eventStorageFileName, i) + if e != nil { + logging.Error("FAILED TO TRUNCATE EVENT STORE!!") + logging.Error("You will likely have garbage data at the end of it") + logging.Error("Attempt manual correction!") + } +} + type EventType int8 const ( diff --git a/main.go b/main.go index ea3952c..21111e9 100644 --- a/main.go +++ b/main.go @@ -3,8 +3,6 @@ package main import ( "flag" "log" - "os" - "os/signal" "gitlab.com/whom/bingobot/internal/config" "gitlab.com/whom/bingobot/internal/discord" @@ -17,8 +15,6 @@ var ( ) func main() { - flag.Parse() - var err error err = config.Init() @@ -28,6 +24,7 @@ func main() { } logging.Init() + flag.Parse() if err := state.Init( config.Get().InMemoryEventCacheSize, @@ -35,6 +32,7 @@ func main() { ); err != nil { log.Fatalf("couldn't initialize state engine: %s", err.Error()) } + defer state.Teardown() err = startBot() @@ -50,10 +48,6 @@ func startBot() error { return err } - sigch := make(chan os.Signal, 1) - signal.Notify(sigch, os.Interrupt) - <-sigch - logging.Info("shutting down gracefully", "type", "shutdown") discord.Close()