fix(release): 收紧分发热路径与事务边界
bat-rust / Build and test Rust (push) Canceled after 0s
bat-rust / Build and test Go API (push) Canceled after 0s

This commit is contained in:
2026-09-12 22:22:11 +08:00
parent f2c20367a6
commit 786b739f99
17 changed files with 835 additions and 124 deletions
+1 -1
View File
@@ -109,7 +109,7 @@ paths:
type: string
- name: destination
in: query
description: Optional release-relative path whose localized bytes and BLAKE3 are revalidated.
description: Optional release-relative path for single-entry lookup; Rust returns exactly one entry and revalidates the selected channel's actual bytes and BLAKE3.
schema:
type: string
- name: offset
+10 -1
View File
@@ -194,9 +194,18 @@ func (s *Server) loadReleaseDistributionFrom(r *http.Request, params backendrpc.
}
pageSize := 1000
result, err := backend.ReleaseDistribution(r.Context(), params)
if err != nil || result == nil || !result.Available || result.Total <= len(result.Entries) {
if err != nil || result == nil || !result.Available {
return result, err
}
if params.Destination != "" {
if result.Total != 1 || result.Offset != 0 || result.Limit != 1 || len(result.Entries) != 1 {
return nil, &releaseSelectorError{message: "Rust single-entry release distribution response is invalid"}
}
return result, nil
}
if result.Total <= len(result.Entries) {
return result, nil
}
all := append([]backendrpc.ReleaseDistributionEntry(nil), result.Entries...)
for offset := len(all); offset < result.Total; {
next, nextErr := backend.ReleaseDistribution(r.Context(), backendrpc.ReleaseDistributionParams{
+204 -4
View File
@@ -4,6 +4,9 @@ import (
"context"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
@@ -15,6 +18,49 @@ type releaseBackendStub struct {
root string
available bool
distributionParams []backendrpc.ReleaseDistributionParams
largeDistribution bool
}
type variableDistributionBackend struct {
*releaseBackendStub
officialRoot string
localizedRoot string
officialBytes []byte
localizedBytes []byte
}
func (b *variableDistributionBackend) ReleaseDistribution(_ context.Context, params backendrpc.ReleaseDistributionParams) (*backendrpc.ReleaseDistributionPage, error) {
b.distributionParams = append(b.distributionParams, params)
root := b.officialRoot
data := b.officialBytes
channel := "official"
releaseID := "official-1"
hash := "official-b3"
if params.Channel == "localized" {
root = b.localizedRoot
data = b.localizedBytes
channel = "localized"
releaseID = "localized-1"
hash = "localized-b3"
}
return &backendrpc.ReleaseDistributionPage{
Available: true,
Channel: channel,
ReleaseID: releaseID,
ResourceRoot: root,
Status: "ready",
StatusCode: "distribution.ready",
ArtifactIntegrityStatus: "valid",
Total: 1,
Offset: 0,
Limit: 1,
Entries: []backendrpc.ReleaseDistributionEntry{{
URL: "https://prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes",
Destination: "prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes",
Bytes: uint64(len(data)),
BLAKE3: hash,
}},
}, nil
}
func (b *controlBackend) ReleaseStatus(context.Context) (*backendrpc.ReleaseStatusReport, error) {
@@ -63,6 +109,52 @@ func (b *releaseBackendStub) ReleaseList(context.Context, backendrpc.ReleaseList
func (b *releaseBackendStub) ReleaseDistribution(_ context.Context, params backendrpc.ReleaseDistributionParams) (*backendrpc.ReleaseDistributionPage, error) {
b.distributionParams = append(b.distributionParams, params)
if b.largeDistribution {
target := "prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes"
if params.Destination != "" {
return &backendrpc.ReleaseDistributionPage{
Available: b.available,
Channel: params.Channel,
ReleaseID: params.ReleaseID,
ResourceRoot: b.root,
Status: "ready",
StatusCode: "distribution.ready",
ArtifactIntegrityStatus: "valid",
Total: 1,
Offset: 0,
Limit: 1,
Entries: []backendrpc.ReleaseDistributionEntry{{
URL: "https://prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes",
Destination: target,
Bytes: 21,
BLAKE3: "not-used-by-http-index",
}},
}, nil
}
entries := make([]backendrpc.ReleaseDistributionEntry, 5000)
for index := range entries {
entries[index] = backendrpc.ReleaseDistributionEntry{
URL: "https://prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/resource.bytes",
Destination: "prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/resource-" + strconv.Itoa(index) + ".bytes",
Bytes: 21,
BLAKE3: "not-used-by-http-index",
}
}
entries[0].Destination = target
return &backendrpc.ReleaseDistributionPage{
Available: b.available,
Channel: params.Channel,
ReleaseID: params.ReleaseID,
ResourceRoot: b.root,
Status: "ready",
StatusCode: "distribution.ready",
ArtifactIntegrityStatus: "valid",
Total: len(entries),
Offset: 0,
Limit: len(entries),
Entries: entries,
}, nil
}
return &backendrpc.ReleaseDistributionPage{
Available: b.available,
Channel: params.Channel,
@@ -72,7 +164,8 @@ func (b *releaseBackendStub) ReleaseDistribution(_ context.Context, params backe
StatusCode: "distribution.ready",
ArtifactIntegrityStatus: "valid",
Total: 1,
Limit: 1000,
Offset: 0,
Limit: 1,
Entries: []backendrpc.ReleaseDistributionEntry{{
URL: "https://prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes",
Destination: "prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes",
@@ -82,6 +175,113 @@ func (b *releaseBackendStub) ReleaseDistribution(_ context.Context, params backe
}, nil
}
func TestCDNSingleEntryLookupDoesNotPaginateLargeDistribution(t *testing.T) {
cfg := DefaultConfig()
cfg.RequireIndexed = false
if err := cfg.Normalize(); err != nil {
t.Fatal(err)
}
backend := &releaseBackendStub{
fakeBackend: &fakeBackend{},
root: fixtureRoot(t),
available: true,
largeDistribution: true,
}
server := NewServer(cfg, backend, nil)
request := httptest.NewRequest(
http.MethodGet,
"/prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes?channel=localized&release_id=localized-1",
nil,
)
recorder := httptest.NewRecorder()
server.Handler().ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK || recorder.Body.String() != "TABLE_CATALOG_FIXTURE" {
t.Fatalf("large distribution CDN status=%d body=%q", recorder.Code, recorder.Body.String())
}
if len(backend.distributionParams) != 1 {
t.Fatalf("single-entry lookup made %d backend calls", len(backend.distributionParams))
}
params := backend.distributionParams[0]
if params.Destination != "prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes" {
t.Fatalf("single-entry destination=%q", params.Destination)
}
}
func TestCDNUsesLocalizedBytesAndHashForGetAndHead(t *testing.T) {
cfg := DefaultConfig()
cfg.RequireIndexed = false
if err := cfg.Normalize(); err != nil {
t.Fatal(err)
}
rel := filepath.FromSlash("prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes")
officialBytes := []byte("official-A")
localizedBytes := []byte("localized-B-with-a-different-length")
officialRoot := t.TempDir()
localizedRoot := t.TempDir()
if err := os.MkdirAll(filepath.Dir(filepath.Join(officialRoot, rel)), 0o755); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(filepath.Dir(filepath.Join(localizedRoot, rel)), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(officialRoot, rel), officialBytes, 0o644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(localizedRoot, rel), localizedBytes, 0o644); err != nil {
t.Fatal(err)
}
backend := &variableDistributionBackend{
releaseBackendStub: &releaseBackendStub{fakeBackend: &fakeBackend{}},
officialRoot: officialRoot,
localizedRoot: localizedRoot,
officialBytes: officialBytes,
localizedBytes: localizedBytes,
}
server := NewServer(cfg, backend, nil)
localizedURL := "/prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes?channel=localized&release_id=localized-1"
recorder := httptest.NewRecorder()
server.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, localizedURL, nil))
if recorder.Code != http.StatusOK || recorder.Body.String() != string(localizedBytes) {
t.Fatalf("localized GET status=%d body=%q", recorder.Code, recorder.Body.String())
}
if recorder.Header().Get("ETag") != `"blake3-localized-b3"` {
t.Fatalf("localized ETag=%q", recorder.Header().Get("ETag"))
}
if recorder.Result().ContentLength != int64(len(localizedBytes)) {
t.Fatalf("localized Content-Length=%d", recorder.Result().ContentLength)
}
recorder = httptest.NewRecorder()
server.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodHead, localizedURL, nil))
if recorder.Code != http.StatusOK || recorder.Body.Len() != 0 {
t.Fatalf("localized HEAD status=%d body=%d", recorder.Code, recorder.Body.Len())
}
if recorder.Header().Get("ETag") != `"blake3-localized-b3"` ||
recorder.Result().ContentLength != int64(len(localizedBytes)) {
t.Fatalf("localized HEAD headers etag=%q length=%d", recorder.Header().Get("ETag"), recorder.Result().ContentLength)
}
officialURL := "/prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes?channel=official&release_id=official-1"
recorder = httptest.NewRecorder()
server.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, officialURL, nil))
if recorder.Code != http.StatusOK || recorder.Body.String() != string(officialBytes) {
t.Fatalf("official GET status=%d body=%q", recorder.Code, recorder.Body.String())
}
if recorder.Header().Get("ETag") != `"blake3-official-b3"` ||
recorder.Result().ContentLength != int64(len(officialBytes)) {
t.Fatalf("official headers etag=%q length=%d", recorder.Header().Get("ETag"), recorder.Result().ContentLength)
}
if len(backend.distributionParams) != 3 {
t.Fatalf("backend calls=%d want=3", len(backend.distributionParams))
}
for _, params := range backend.distributionParams {
if params.Destination != "prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes" {
t.Fatalf("backend destination=%q", params.Destination)
}
}
}
func (*releaseBackendStub) ReleaseCleanup(context.Context, backendrpc.ReleaseCleanupParams) (*backendrpc.ReleaseCleanupReport, error) {
return &backendrpc.ReleaseCleanupReport{PlanID: "plan-1"}, nil
}
@@ -101,7 +301,7 @@ func TestReleaseHTTPForwardsTypedSelectionAndDoesNotFallback(t *testing.T) {
}
recorder = httptest.NewRecorder()
server.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/v1/distribution?channel=localized&release_id=localized-1&destination=TableBundles%2FTableCatalog.bytes&offset=2&limit=10", nil))
server.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/v1/distribution?channel=localized&release_id=localized-1&destination=TableBundles%2FTableCatalog.bytes", nil))
if recorder.Code != http.StatusOK {
t.Fatalf("distribution status=%d body=%s", recorder.Code, recorder.Body.String())
}
@@ -109,8 +309,8 @@ func TestReleaseHTTPForwardsTypedSelectionAndDoesNotFallback(t *testing.T) {
backend.distributionParams[0].Channel != "localized" ||
backend.distributionParams[0].ReleaseID != "localized-1" ||
backend.distributionParams[0].Destination != "TableBundles/TableCatalog.bytes" ||
backend.distributionParams[0].Offset != 2 ||
backend.distributionParams[0].Limit != 10 {
backend.distributionParams[0].Offset != 0 ||
backend.distributionParams[0].Limit != 0 {
t.Fatalf("distribution params=%#v", backend.distributionParams)
}