1
0
Fork 0
forked from Mirrors/gomuks

hicli/sync: don't fail sync if database is locked

This commit is contained in:
Tulir Asokan 2024-12-17 22:34:54 +02:00
parent 0b1d5cd354
commit 29b787f94a
10 changed files with 37 additions and 20 deletions

View file

@ -8,7 +8,7 @@ require github.com/wailsapp/wails/v3 v3.0.0-alpha.7
require ( require (
go.mau.fi/gomuks v0.3.1 go.mau.fi/gomuks v0.3.1
go.mau.fi/util v0.8.3 go.mau.fi/util v0.8.4-0.20241217203137-4aa8973d6dbc
) )
require ( require (

View file

@ -160,8 +160,8 @@ github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
go.mau.fi/util v0.8.3 h1:sulhXtfquMrQjsOP67x9CzWVBYUwhYeoo8hNQIpCWZ4= go.mau.fi/util v0.8.4-0.20241217203137-4aa8973d6dbc h1:55919oheHZLQktzYU2z9KSJ5KHXq34dYedoGFfdUcsg=
go.mau.fi/util v0.8.3/go.mod h1:c00Db8xog70JeIsEvhdHooylTkTkakgnAOsZ04hplQY= go.mau.fi/util v0.8.4-0.20241217203137-4aa8973d6dbc/go.mod h1:c00Db8xog70JeIsEvhdHooylTkTkakgnAOsZ04hplQY=
go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM=
go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

2
go.mod
View file

@ -17,7 +17,7 @@ require (
github.com/tidwall/gjson v1.18.0 github.com/tidwall/gjson v1.18.0
github.com/tidwall/sjson v1.2.5 github.com/tidwall/sjson v1.2.5
github.com/yuin/goldmark v1.7.8 github.com/yuin/goldmark v1.7.8
go.mau.fi/util v0.8.3 go.mau.fi/util v0.8.4-0.20241217203137-4aa8973d6dbc
go.mau.fi/zeroconfig v0.1.3 go.mau.fi/zeroconfig v0.1.3
golang.org/x/crypto v0.31.0 golang.org/x/crypto v0.31.0
golang.org/x/image v0.23.0 golang.org/x/image v0.23.0

4
go.sum
View file

@ -63,8 +63,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
go.mau.fi/util v0.8.3 h1:sulhXtfquMrQjsOP67x9CzWVBYUwhYeoo8hNQIpCWZ4= go.mau.fi/util v0.8.4-0.20241217203137-4aa8973d6dbc h1:55919oheHZLQktzYU2z9KSJ5KHXq34dYedoGFfdUcsg=
go.mau.fi/util v0.8.3/go.mod h1:c00Db8xog70JeIsEvhdHooylTkTkakgnAOsZ04hplQY= go.mau.fi/util v0.8.4-0.20241217203137-4aa8973d6dbc/go.mod h1:c00Db8xog70JeIsEvhdHooylTkTkakgnAOsZ04hplQY=
go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM=
go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=

View file

@ -44,9 +44,10 @@ func (c *SyncComplete) IsEmpty() bool {
type SyncStatusType string type SyncStatusType string
const ( const (
SyncStatusOK SyncStatusType = "ok" SyncStatusOK SyncStatusType = "ok"
SyncStatusWaiting SyncStatusType = "waiting" SyncStatusWaiting SyncStatusType = "waiting"
SyncStatusErrored SyncStatusType = "errored" SyncStatusErroring SyncStatusType = "erroring"
SyncStatusFailed SyncStatusType = "permanently-failed"
) )
type SyncStatus struct { type SyncStatus struct {

View file

@ -252,7 +252,7 @@ func (h *HiClient) Sync() {
log.Info().Msg("Starting syncing") log.Info().Msg("Starting syncing")
err := h.Client.SyncWithContext(ctx) err := h.Client.SyncWithContext(ctx)
if err != nil && ctx.Err() == nil { if err != nil && ctx.Err() == nil {
h.markSyncErrored(err) h.markSyncErrored(err, true)
log.Err(err).Msg("Fatal error in syncer") log.Err(err).Msg("Fatal error in syncer")
} else { } else {
h.SyncStatus.Store(syncWaiting) h.SyncStatus.Store(syncWaiting)

View file

@ -39,13 +39,16 @@ type syncContext struct {
evt *SyncComplete evt *SyncComplete
} }
func (h *HiClient) markSyncErrored(err error) { func (h *HiClient) markSyncErrored(err error, permanent bool) {
stat := &SyncStatus{ stat := &SyncStatus{
Type: SyncStatusErrored, Type: SyncStatusErroring,
Error: err.Error(), Error: err.Error(),
ErrorCount: h.syncErrors, ErrorCount: h.syncErrors,
LastSync: jsontime.UM(h.lastSync), LastSync: jsontime.UM(h.lastSync),
} }
if permanent {
stat.Type = SyncStatusFailed
}
h.SyncStatus.Store(stat) h.SyncStatus.Store(stat)
h.EventHandler(stat) h.EventHandler(stat)
} }

View file

@ -8,9 +8,11 @@ package hicli
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"time" "time"
"github.com/mattn/go-sqlite3"
"maunium.net/go/mautrix" "maunium.net/go/mautrix"
"maunium.net/go/mautrix/id" "maunium.net/go/mautrix/id"
) )
@ -37,11 +39,18 @@ func (h *hiSyncer) ProcessResponse(ctx context.Context, resp *mautrix.RespSync,
if err != nil { if err != nil {
return err return err
} }
err = c.DB.DoTxn(ctx, nil, func(ctx context.Context) error { for i := 0; ; i++ {
return c.processSyncResponse(ctx, resp, since) err = c.DB.DoTxn(ctx, nil, func(ctx context.Context) error {
}) return c.processSyncResponse(ctx, resp, since)
if err != nil { })
return err if errors.Is(err, sqlite3.ErrLocked) && i < 24 {
c.markSyncErrored(err, false)
continue
} else if err != nil {
return err
} else {
break
}
} }
c.postProcessSyncResponse(ctx, resp, since) c.postProcessSyncResponse(ctx, resp, since)
c.syncErrors = 0 c.syncErrors = 0
@ -56,7 +65,7 @@ func (h *hiSyncer) OnFailedSync(_ *mautrix.RespSync, err error) (time.Duration,
if c.syncErrors > 5 { if c.syncErrors > 5 {
delay = max(time.Duration(c.syncErrors)*time.Second, 30*time.Second) delay = max(time.Duration(c.syncErrors)*time.Second, 30*time.Second)
} }
c.markSyncErrored(err) c.markSyncErrored(err, false)
c.Log.Err(err).Dur("retry_in", delay).Msg("Sync failed") c.Log.Err(err).Dur("retry_in", delay).Msg("Sync failed")
return delay, nil return delay, nil
} }

View file

@ -110,7 +110,7 @@ export interface ClientStateEvent extends BaseRPCCommand<ClientState> {
} }
export interface SyncStatus { export interface SyncStatus {
type: "ok" | "waiting" | "errored" type: "ok" | "waiting" | "erroring" | "permanently-failed"
error?: string error?: string
error_count: number error_count: number
last_sync?: number last_sync?: number

View file

@ -302,13 +302,17 @@ const MainScreen = () => {
Waiting for first sync... Waiting for first sync...
</div> </div>
} else if ( } else if (
syncStatus.type === "errored" syncStatus.type === "erroring"
&& (syncStatus.error_count > 2 || (syncStatus.last_sync ?? 0) + SYNC_ERROR_HIDE_DELAY < Date.now()) && (syncStatus.error_count > 2 || (syncStatus.last_sync ?? 0) + SYNC_ERROR_HIDE_DELAY < Date.now())
) { ) {
syncLoader = <div className="sync-status errored" title={syncStatus.error}> syncLoader = <div className="sync-status errored" title={syncStatus.error}>
<SyncLoader color="var(--error-color)"/> <SyncLoader color="var(--error-color)"/>
Sync is failing Sync is failing
</div> </div>
} else if (syncStatus.type === "permanently-failed") {
syncLoader = <div className="sync-status errored" title={syncStatus.error}>
Sync failed permanently
</div>
} }
const renderedRoom = activeRoom ?? prevActiveRoom const renderedRoom = activeRoom ?? prevActiveRoom
useEffect(() => { useEffect(() => {