Two blob-cleanup defects: - OSS driver diffed `files` (the whole request) instead of `group` (the current 1000-key batch) when computing undeleted keys — every batch beyond the first was pre-marked failed, so deleted blobs kept their DB rows and the sweep re-tried them forever. - A blob that can never be deleted (illegal over-long path, corrupted key) blocked the routine sweep indefinitely: every run re-attempted it, errored the task, and repeated. EntityProps gains a JSON `recycle_fail_count`; per-entity failures increment it (whole-chunk failures are treated as infra outages and never count), and past RecycleFailThreshold (5) the row is force-removed with a loud warning rather than stalling cleanup forever. Authored By: TDvorak <info@tdvorak.dev> Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>pull/3582/head
parent
fb96eaebaa
commit
04583175bb
@ -0,0 +1,52 @@
|
|||||||
|
package inventory
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cloudreve/Cloudreve/v4/ent/enttest"
|
||||||
|
"github.com/cloudreve/Cloudreve/v4/inventory/types"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUpdateEntityProps(t *testing.T) {
|
||||||
|
client := enttest.Open(t, "sqlite3", "file:"+t.Name()+"?mode=memory&cache=shared")
|
||||||
|
t.Cleanup(func() { require.NoError(t, client.Close()) })
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
policy := client.StoragePolicy.Create().
|
||||||
|
SetName("local").
|
||||||
|
SetType(string(types.PolicyTypeLocal)).
|
||||||
|
SetBucketName("bucket").
|
||||||
|
SetAccessKey("ak").
|
||||||
|
SetSecretKey("sk").
|
||||||
|
SetMaxSize(0).
|
||||||
|
SetDirNameRule("d").
|
||||||
|
SetFileNameRule("f").
|
||||||
|
SaveX(ctx)
|
||||||
|
|
||||||
|
e := client.Entity.Create().
|
||||||
|
SetType(int(types.EntityTypeVersion)).
|
||||||
|
SetSource("uploads/1/test.bin").
|
||||||
|
SetSize(100).
|
||||||
|
SetStoragePolicyEntities(policy.ID).
|
||||||
|
SaveX(ctx)
|
||||||
|
|
||||||
|
c := NewFileClient(client, "sqlite3", nil)
|
||||||
|
|
||||||
|
e.Props = &types.EntityProps{RecycleFailCount: 3}
|
||||||
|
require.NoError(t, c.UpdateEntityProps(ctx, e))
|
||||||
|
|
||||||
|
got := client.Entity.GetX(ctx, e.ID)
|
||||||
|
require.NotNil(t, got.Props)
|
||||||
|
require.Equal(t, 3, got.Props.RecycleFailCount)
|
||||||
|
|
||||||
|
// Other props survive a partial update.
|
||||||
|
e.Props.RecycleFailCount = 5
|
||||||
|
e.Props.UnlinkOnly = true
|
||||||
|
require.NoError(t, c.UpdateEntityProps(ctx, e))
|
||||||
|
|
||||||
|
got = client.Entity.GetX(ctx, e.ID)
|
||||||
|
require.Equal(t, 5, got.Props.RecycleFailCount)
|
||||||
|
require.True(t, got.Props.UnlinkOnly)
|
||||||
|
}
|
||||||
Loading…
Reference in new issue