mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
feat(multiplayer): add shared allocation quota
This commit is contained in:
@@ -30,11 +30,16 @@ type AllocationBudget interface {
|
||||
Allow(region string, now time.Time) error
|
||||
}
|
||||
|
||||
type SharedAllocationQuota interface {
|
||||
Consume(context.Context, string, time.Time) error
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
Provider Provider
|
||||
Durable Durable
|
||||
Roster RosterPublisher
|
||||
Budget AllocationBudget
|
||||
Quota SharedAllocationQuota
|
||||
Now func() time.Time
|
||||
}
|
||||
|
||||
@@ -88,6 +93,11 @@ func (s Service) Allocate(ctx context.Context, request domain.AllocationRequest,
|
||||
return agones.AllocatedServer{}, err
|
||||
}
|
||||
}
|
||||
if s.Quota != nil {
|
||||
if err := s.Quota.Consume(ctx, request.Region, now); err != nil {
|
||||
return agones.AllocatedServer{}, err
|
||||
}
|
||||
}
|
||||
result, err := s.Provider.Allocate(ctx, request, labels, now)
|
||||
if err != nil {
|
||||
return agones.AllocatedServer{}, err
|
||||
@@ -102,6 +112,11 @@ func (s Service) RecordProviderAllocation(ctx context.Context, result agones.All
|
||||
if s.Durable == nil || result.Allocation.State != domain.ServerAllocated || result.Endpoint == "" {
|
||||
return domain.Allocation{}, domain.ErrAllocationInput
|
||||
}
|
||||
if s.Quota != nil {
|
||||
if err := s.Quota.Consume(ctx, result.Allocation.Region, now); err != nil {
|
||||
return domain.Allocation{}, err
|
||||
}
|
||||
}
|
||||
return s.Durable.RecordProviderAllocation(ctx, result.Allocation, now)
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,16 @@ type rosterSpy struct {
|
||||
err error
|
||||
}
|
||||
|
||||
type quotaSpy struct {
|
||||
calls int
|
||||
err error
|
||||
}
|
||||
|
||||
func (q *quotaSpy) Consume(context.Context, string, time.Time) error {
|
||||
q.calls++
|
||||
return q.err
|
||||
}
|
||||
|
||||
func (r *rosterSpy) PublishRoster(_ context.Context, _ domain.Assignment, _ []domain.SignedJoinAuthorisation, _ func([]byte, []byte) bool) error {
|
||||
r.calls++
|
||||
return r.err
|
||||
@@ -63,6 +73,31 @@ func TestServiceDoesNotReturnProviderResultAfterDurableFailure(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceConsumesSharedQuotaBeforeFreshProviderCall(t *testing.T) {
|
||||
provider := &providerSpy{result: agones.AllocatedServer{Allocation: domain.Allocation{AllocationID: "a", State: domain.ServerAllocated}, Endpoint: "127.0.0.1:7777"}}
|
||||
quota := "aSpy{err: errors.New("quota exhausted")}
|
||||
service := Service{Provider: provider, Durable: &durableSpy{}, Quota: quota, Now: func() time.Time { return time.Unix(1000, 0) }}
|
||||
if _, err := service.Allocate(context.Background(), domain.AllocationRequest{AllocationID: "a", MatchID: "m", Region: "EU", Build: "b", Protocol: 1, Transport: "enet"}, nil); err == nil {
|
||||
t.Fatal("quota rejection was ignored")
|
||||
}
|
||||
if quota.calls != 1 || provider.calls != 0 {
|
||||
t.Fatalf("quota/provider calls = %d/%d, want 1/0", quota.calls, provider.calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceConsumesSharedQuotaOnceWhenReconcilingProviderResult(t *testing.T) {
|
||||
quota := "aSpy{}
|
||||
durable := &durableSpy{}
|
||||
service := Service{Durable: durable, Quota: quota, Now: func() time.Time { return time.Unix(1000, 0) }}
|
||||
result := agones.AllocatedServer{Allocation: domain.Allocation{AllocationID: "a", MatchID: "m", Region: "EU", State: domain.ServerAllocated}, Endpoint: "127.0.0.1:7777"}
|
||||
if _, err := service.RecordProviderAllocation(context.Background(), result, time.Unix(1000, 0)); err != nil {
|
||||
t.Fatalf("reconciliation failed: %v", err)
|
||||
}
|
||||
if quota.calls != 1 || durable.calls != 1 {
|
||||
t.Fatalf("quota/durable calls = %d/%d, want 1/1", quota.calls, durable.calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceAllocatesOnlyUnanimouslyAcceptedMatchingProposal(t *testing.T) {
|
||||
proposal := domain.Proposal{
|
||||
ProposalID: "proposal-1", Playlist: domain.Casual, State: domain.Accepted,
|
||||
|
||||
Reference in New Issue
Block a user