fix(syncthing): apply folder migrations with temporary API/GUI server (#10330)

Prevent the feeling that nothing is happening / it's not starting.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
Jakob Borg
2025-09-01 22:10:48 +02:00
committed by GitHub
parent fafc3ba45e
commit 541678ad9e
5 changed files with 65 additions and 41 deletions
-4
View File
@@ -191,10 +191,6 @@ func (a *App) startup() error {
if _, ok := cfgFolders[folder]; !ok {
slog.Info("Cleaning metadata for dropped folder", "folder", folder)
a.sdb.DropFolder(folder)
} else {
// Open the folder database, causing it to apply migrations
// early when appropriate.
_, _ = a.sdb.GetDeviceSequence(folder, protocol.LocalDeviceID)
}
}
+1 -34
View File
@@ -13,7 +13,6 @@ import (
"fmt"
"io"
"log/slog"
"net/http"
"os"
"sync"
"time"
@@ -159,7 +158,7 @@ func OpenDatabase(path string, deleteRetention time.Duration) (db.DB, error) {
// Attempts migration of the old (LevelDB-based) database type to the new (SQLite-based) type
// This will attempt to provide a temporary API server during the migration, if `apiAddr` is not empty.
func TryMigrateDatabase(ctx context.Context, deleteRetention time.Duration, apiAddr string) error {
func TryMigrateDatabase(ctx context.Context, deleteRetention time.Duration) error {
oldDBDir := locations.Get(locations.LegacyDatabase)
if _, err := os.Lstat(oldDBDir); err != nil {
// No old database
@@ -173,14 +172,6 @@ func TryMigrateDatabase(ctx context.Context, deleteRetention time.Duration, apiA
}
defer be.Close()
// Start a temporary API server during the migration
if apiAddr != "" {
api := migratingAPI{addr: apiAddr}
apiCtx, cancel := context.WithCancel(ctx)
defer cancel()
go api.Serve(apiCtx)
}
sdb, err := sqlite.OpenForMigration(locations.Get(locations.Database))
if err != nil {
return err
@@ -295,27 +286,3 @@ func TryMigrateDatabase(ctx context.Context, deleteRetention time.Duration, apiA
slog.Info("Migration complete", "files", totFiles, "blocks", totBlocks/1000, "duration", time.Since(t0).Truncate(time.Second))
return nil
}
type migratingAPI struct {
addr string
}
func (m migratingAPI) Serve(ctx context.Context) error {
srv := &http.Server{
Addr: m.addr,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("*** Database migration in progress ***\n\n"))
for _, line := range slogutil.GlobalRecorder.Since(time.Time{}) {
line.WriteTo(w)
}
}),
}
go func() {
slog.InfoContext(ctx, "Starting temporary GUI/API during migration", slogutil.Address(m.addr))
err := srv.ListenAndServe()
slog.InfoContext(ctx, "Temporary GUI/API closed", slogutil.Address(m.addr), slogutil.Error(err))
}()
<-ctx.Done()
return srv.Close()
}