Fix atomic latest version update to prevent missing isLatest flags (#530)
## Summary Fixes a race condition where a server could have no version marked as `isLatest` if the database operations failed independently. ## Changes - **CreateServer signature**: Now accepts `oldLatestVersionID` parameter to atomically unmark previous latest version - **PostgreSQL implementation**: Uses a transaction to ensure UPDATE (unmark old latest) and INSERT (create new version) happen atomically - **Service layer**: Maintains `WithPublishLock` for concurrent operation serialization - **Two-level protection**: Advisory lock prevents races, transaction ensures atomicity ## Test plan - [x] Existing race condition tests pass - [x] Integration tests pass - [x] Unit tests pass 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
ae00f70eaf
commit
747ad310bb
2 changed files with 243 additions and 233 deletions
|
|
@ -37,7 +37,7 @@ func (s *Service) ImportFromPath(ctx context.Context, path string) error {
|
|||
|
||||
// Import each server using CreateServer
|
||||
for _, server := range servers {
|
||||
_, err := s.db.CreateServer(ctx, server)
|
||||
_, err := s.db.CreateServer(ctx, nil, server)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to import server %s: %w", server.Name, err)
|
||||
}
|
||||
|
|
@ -181,4 +181,4 @@ func convertServerResponseToRecord(response apiv0.ServerJSON) *apiv0.ServerJSON
|
|||
// The response is already in the correct flattened format
|
||||
// Just return a pointer to it
|
||||
return &response
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ func TestImportService_LocalFile(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// Verify the server was imported
|
||||
servers, _, err := testDB.List(context.Background(), nil, "", 10)
|
||||
servers, _, err := testDB.List(context.Background(), nil, nil, "", 10)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, servers, 1)
|
||||
assert.Equal(t, "io.github.test/test-server-1", servers[0].Name)
|
||||
|
|
@ -101,7 +101,7 @@ func TestImportService_HTTPFile(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// Verify the server was imported
|
||||
servers, _, err := testDB.List(context.Background(), nil, "", 10)
|
||||
servers, _, err := testDB.List(context.Background(), nil, nil, "", 10)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, servers, 1)
|
||||
assert.Equal(t, "io.github.test/http-test-server", servers[0].Name)
|
||||
|
|
@ -187,7 +187,7 @@ func TestImportService_RegistryAPI(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// Verify both servers were imported
|
||||
servers, _, err := testDB.List(context.Background(), nil, "", 10)
|
||||
servers, _, err := testDB.List(context.Background(), nil, nil, "", 10)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, servers, 2)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue