From cc4b4536243b04234b74cb5dfdb6b9da425971b9 Mon Sep 17 00:00:00 2001 From: Natercio Moniz Date: Sun, 2 Aug 2026 22:05:49 +0100 Subject: [PATCH] preserve old file --- internal/file_store.go | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/internal/file_store.go b/internal/file_store.go index 0f16cd9..4a099ff 100644 --- a/internal/file_store.go +++ b/internal/file_store.go @@ -9,6 +9,9 @@ import ( "io" "os" "path/filepath" + "strconv" + "strings" + "time" ) // FileStore is a Store backed by a single JSON file on disk. The on-disk @@ -121,6 +124,16 @@ func (fs *FileStore) Save(ctx context.Context, queue map[string]*FillerQueue) er state.Queues[symbol] = persisted } + ext := filepath.Ext(fs.filename) + name, _ := strings.CutSuffix(fs.filename, ext) + backupFilename := name + "." + strconv.FormatInt(time.Now().UnixMilli(), 10) + ext + err := os.Rename(fs.filename, backupFilename) + if err != nil { + if !errors.Is(err, os.ErrNotExist) { + return fmt.Errorf("rename old state file: %w", err) + } + } + buf := &bytes.Buffer{} enc := json.NewEncoder(buf) enc.SetIndent("", " ") @@ -128,27 +141,13 @@ func (fs *FileStore) Save(ctx context.Context, queue map[string]*FillerQueue) er return fmt.Errorf("encoding state: %w", err) } - dir := filepath.Dir(fs.filename) - tmp, err := os.CreateTemp(dir, ".state-*.tmp") + dst, err := os.Create(fs.filename) if err != nil { - return fmt.Errorf("creating temp file: %w", err) + return fmt.Errorf("creating new state file: %w", err) } - tmpName := tmp.Name() - // Best-effort cleanup if rename never runs (e.g. process killed between - // CreateTemp and Rename). On success the temp file has been consumed by - // Rename and Remove returns ENOENT which we ignore. - defer os.Remove(tmpName) - - if _, err := io.Copy(tmp, buf); err != nil { - _ = tmp.Close() - return fmt.Errorf("writing temp file: %w", err) - } - if err := tmp.Close(); err != nil { - return fmt.Errorf("closing temp file: %w", err) - } - if err := os.Rename(tmpName, fs.filename); err != nil { - return fmt.Errorf("renaming temp file: %w", err) + if _, err := io.Copy(dst, buf); err != nil { + return fmt.Errorf("writing to new state file: %w", err) } return nil }