收窄 assignment 队列职责

This commit is contained in:
2026-09-20 19:06:04 +00:00
parent 27787d7899
commit a856176c56
5 changed files with 98 additions and 113 deletions
+12 -51
View File
@@ -52,32 +52,25 @@ func TestPublisherUsesBackendSubjectAndAssignmentDeduplication(t *testing.T) {
}
}
type fakeHandler struct {
done bool
err error
remaining int
type fakeAccepter struct {
accepted bool
err error
}
func (h *fakeHandler) Handle(context.Context, taskassignment.Assignment) (bool, error) {
if h.remaining > 0 {
h.remaining--
return false, nil
}
return h.done, h.err
func (a *fakeAccepter) Accept(context.Context, taskassignment.Assignment) (bool, error) {
return a.accepted, a.err
}
type fakeMessage struct {
data []byte
acked int
nacked time.Duration
inProgress int
terminated int
}
func (m *fakeMessage) Data() []byte { return m.data }
func (m *fakeMessage) DoubleAck(context.Context) error { m.acked++; return nil }
func (m *fakeMessage) NakWithDelay(delay time.Duration) error { m.nacked = delay; return nil }
func (m *fakeMessage) InProgress() error { m.inProgress++; return nil }
func (m *fakeMessage) TermWithReason(string) error { m.terminated++; return nil }
func encodedAssignment(t *testing.T) []byte {
@@ -89,24 +82,24 @@ func encodedAssignment(t *testing.T) []byte {
return data
}
func TestProcessorAcknowledgesOnlyCompletedAssignment(t *testing.T) {
func TestProcessorAcknowledgesPersistedHandoff(t *testing.T) {
message := &fakeMessage{data: encodedAssignment(t)}
processor := Processor{TrustDomain: "ddupan.top", Handler: &fakeHandler{done: true}}
processor := Processor{TrustDomain: "ddupan.top", Accepter: &fakeAccepter{accepted: true}}
if err := processor.Process(context.Background(), message); err != nil {
t.Fatal(err)
}
if message.acked != 1 || message.inProgress != 0 || message.nacked != 0 {
if message.acked != 1 || message.nacked != 0 {
t.Fatalf("message = %#v", message)
}
}
func TestProcessorKeepsRunningAssignmentPending(t *testing.T) {
func TestProcessorRetriesUntilBackendHandoffIsDurable(t *testing.T) {
message := &fakeMessage{data: encodedAssignment(t)}
processor := Processor{TrustDomain: "ddupan.top", Handler: &fakeHandler{}}
processor := Processor{TrustDomain: "ddupan.top", Accepter: &fakeAccepter{}, RetryDelay: 2 * time.Second}
if err := processor.Process(context.Background(), message); err != nil {
t.Fatal(err)
}
if message.acked != 0 || message.inProgress != 1 {
if message.acked != 0 || message.nacked != 2*time.Second {
t.Fatalf("message = %#v", message)
}
}
@@ -115,7 +108,7 @@ func TestProcessorRetriesBackendFailureAndTerminatesPoisonMessage(t *testing.T)
retry := &fakeMessage{data: encodedAssignment(t)}
processor := Processor{
TrustDomain: "ddupan.top",
Handler: &fakeHandler{err: errors.New("backend unavailable")},
Accepter: &fakeAccepter{err: errors.New("backend unavailable")},
RetryDelay: time.Minute,
}
if err := processor.Process(context.Background(), retry); err == nil {
@@ -134,38 +127,6 @@ func TestProcessorRetriesBackendFailureAndTerminatesPoisonMessage(t *testing.T)
}
}
func TestProcessUntilDoneReconcilesWithoutRedelivery(t *testing.T) {
message := &fakeMessage{data: encodedAssignment(t)}
processor := Processor{
TrustDomain: "ddupan.top",
Handler: &fakeHandler{done: true, remaining: 2},
PollInterval: time.Millisecond,
}
if err := processor.ProcessUntilDone(context.Background(), message); err != nil {
t.Fatal(err)
}
if message.inProgress != 2 || message.acked != 1 || message.nacked != 0 {
t.Fatalf("message = %#v", message)
}
}
func TestProcessUntilDoneLeavesMessagePendingOnShutdown(t *testing.T) {
message := &fakeMessage{data: encodedAssignment(t)}
processor := Processor{
TrustDomain: "ddupan.top",
Handler: &fakeHandler{},
PollInterval: time.Hour,
}
ctx, cancel := context.WithCancel(context.Background())
cancel()
if err := processor.ProcessUntilDone(ctx, message); !errors.Is(err, context.Canceled) {
t.Fatalf("error = %v", err)
}
if message.acked != 0 || message.nacked != 0 || message.terminated != 0 {
t.Fatalf("message = %#v", message)
}
}
type fakeConsumerManager struct{ config jetstream.ConsumerConfig }
func (m *fakeConsumerManager) CreateOrUpdateConsumer(_ context.Context, _ string, config jetstream.ConsumerConfig) (jetstream.Consumer, error) {