mirror of
https://github.com/go-gitea/gitea.git
synced 2026-06-30 22:35:55 +02:00
fix(archiver): use serializable repo-archive queue payload (#38273)
After upgrading from 1.25.x to 1.26.x, `repo-archive` workers can fail to unmarshal queued items: ``` Failed to unmarshal item from queue "repo-archive": json: unable to unmarshal into Go convert.Conversion within "/Repo/Units/0/Config": cannot derive concrete type for nil interface with finite type set ``` `ArchiveRequest` started embedding `*repo_model.Repository` in 1.26, which does not round-trip through the JSON queue. This change stores a minimal `archiveQueueItem` (`RepoID`, `Type`, `CommitID`, `Paths`) in `repo-archive` and loads the repository in the worker. `UnmarshalJSON` accepts legacy payloads that used `RepoID` or embedded `Repo.id`. Fixes #38272 <!-- Before submitting: - Target the `main` branch; release branches are for backports only. - Use a Conventional Commits title, e.g. `fix(repo): handle empty branch names`. - Read the contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md - Documentation changes go to https://gitea.com/gitea/docs Describe your change below and link any issue it fixes. --> --------- Co-authored-by: bircni <bircni@icloud.com>
This commit is contained in:
parent
a64131e22d
commit
e1cdb71845
@ -42,6 +42,38 @@ type ArchiveRequest struct {
|
||||
archiveRefShortName string // the ref short name to download the archive, for example: "master", "v1.0.0", "commit id"
|
||||
}
|
||||
|
||||
type archiveQueueItem struct {
|
||||
RepoID int64 `json:"RepoID"`
|
||||
Type repo_model.ArchiveType `json:"Type"`
|
||||
CommitID string `json:"CommitID"`
|
||||
Paths []string `json:"Paths,omitempty"`
|
||||
ArchiveRefShortName string `json:"ArchiveRefShortName,omitempty"`
|
||||
}
|
||||
|
||||
func (aReq *ArchiveRequest) toQueueItem() *archiveQueueItem {
|
||||
return &archiveQueueItem{
|
||||
RepoID: aReq.Repo.ID,
|
||||
Type: aReq.Type,
|
||||
CommitID: aReq.CommitID,
|
||||
Paths: aReq.Paths,
|
||||
ArchiveRefShortName: aReq.archiveRefShortName,
|
||||
}
|
||||
}
|
||||
|
||||
func (item *archiveQueueItem) toArchiveRequest(ctx context.Context) (*ArchiveRequest, error) {
|
||||
repo, err := repo_model.GetRepositoryByID(ctx, item.RepoID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ArchiveRequest{
|
||||
Repo: repo,
|
||||
Type: item.Type,
|
||||
CommitID: item.CommitID,
|
||||
Paths: item.Paths,
|
||||
archiveRefShortName: item.ArchiveRefShortName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewRequest creates an archival request, based on the URI. The
|
||||
// resulting ArchiveRequest is suitable for being passed to Await()
|
||||
// if it's determined that the request still needs to be satisfied.
|
||||
@ -227,13 +259,18 @@ func doArchive(ctx context.Context, r *ArchiveRequest) (*repo_model.RepoArchiver
|
||||
return archiver, nil
|
||||
}
|
||||
|
||||
var archiverQueue *queue.WorkerPoolQueue[*ArchiveRequest]
|
||||
var archiverQueue *queue.WorkerPoolQueue[*archiveQueueItem]
|
||||
|
||||
// Init initializes archiver
|
||||
func Init(ctx context.Context) error {
|
||||
handler := func(items ...*ArchiveRequest) []*ArchiveRequest {
|
||||
for _, archiveReq := range items {
|
||||
log.Trace("ArchiverData Process: %#v", archiveReq)
|
||||
handler := func(items ...*archiveQueueItem) []*archiveQueueItem {
|
||||
for _, item := range items {
|
||||
log.Trace("ArchiverData Process: %#v", item)
|
||||
archiveReq, err := item.toArchiveRequest(ctx)
|
||||
if err != nil {
|
||||
log.Error("Archive repo %d: %v", item.RepoID, err)
|
||||
continue
|
||||
}
|
||||
if archiver, err := doArchive(ctx, archiveReq); err != nil {
|
||||
log.Error("Archive %v failed: %v", archiveReq, err)
|
||||
} else {
|
||||
@ -254,14 +291,15 @@ func Init(ctx context.Context) error {
|
||||
|
||||
// StartArchive push the archive request to the queue
|
||||
func StartArchive(request *ArchiveRequest) error {
|
||||
has, err := archiverQueue.Has(request)
|
||||
item := request.toQueueItem()
|
||||
has, err := archiverQueue.Has(item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if has {
|
||||
return nil
|
||||
}
|
||||
return archiverQueue.Push(request)
|
||||
return archiverQueue.Push(item)
|
||||
}
|
||||
|
||||
func deleteOldRepoArchiver(ctx context.Context, archiver *repo_model.RepoArchiver) error {
|
||||
|
||||
@ -7,7 +7,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
repo_model "gitea.dev/models/repo"
|
||||
"gitea.dev/models/unittest"
|
||||
"gitea.dev/modules/json"
|
||||
"gitea.dev/modules/util"
|
||||
"gitea.dev/services/contexttest"
|
||||
|
||||
@ -21,6 +23,22 @@ func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m)
|
||||
}
|
||||
|
||||
func TestArchiveQueueItemJSON(t *testing.T) {
|
||||
orig := &archiveQueueItem{
|
||||
RepoID: 7,
|
||||
Type: repo_model.ArchiveZip,
|
||||
CommitID: "abc123",
|
||||
Paths: []string{"agents"},
|
||||
ArchiveRefShortName: "main",
|
||||
}
|
||||
bs, err := json.Marshal(orig)
|
||||
require.NoError(t, err)
|
||||
|
||||
var decoded archiveQueueItem
|
||||
require.NoError(t, json.Unmarshal(bs, &decoded))
|
||||
assert.Equal(t, *orig, decoded)
|
||||
}
|
||||
|
||||
func TestArchive_Basic(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user