feat: add durable business task outbox example and fault recovery
This commit is contained in:
63
examples/task-outbox/internal/outbox/store_test.go
Normal file
63
examples/task-outbox/internal/outbox/store_test.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package outbox
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
orbit "git.yuntuo.hk/k2safe/orbit/sdk/go"
|
||||
)
|
||||
|
||||
func testID(t *testing.T) string {
|
||||
t.Helper()
|
||||
id, err := orbit.NewEventMessageID()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
func testRequest(queue string) orbit.SubmitTaskRequest {
|
||||
return orbit.SubmitTaskRequest{QueueID: queue, Handler: "object.prepare", HandlerVersion: "v1", PayloadVersion: "v1", Payload: json.RawMessage(`{"sequence":9007199254740993,"ref":"objects/test"}`), TaskTimeoutMS: 60000}
|
||||
}
|
||||
func TestFrozenDocumentAndFailureClassification(t *testing.T) {
|
||||
s := &Store{namespace: testID(t), queue: testID(t)}
|
||||
in := testRequest(s.queue)
|
||||
in.TaskTimeoutMS = 0
|
||||
raw, err := s.document(in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var frozen orbit.SubmitTaskRequest
|
||||
if json.Unmarshal(raw, &frozen) != nil || frozen.TaskTimeoutMS != 86400000 || frozen.Retry.MaxAttempts != 1 || frozen.Retry.AttemptTimeoutMS != 30000 || !bytes.Contains(frozen.Payload, []byte("9007199254740993")) {
|
||||
t.Fatal("frozen defaults or precision changed")
|
||||
}
|
||||
in.QueueID = testID(t)
|
||||
if _, err = s.document(in); !errors.Is(err, ErrInvalid) {
|
||||
t.Fatal("cross queue request frozen")
|
||||
}
|
||||
in = testRequest(s.queue)
|
||||
in.BusinessKey = "operation-\xff"
|
||||
if _, err = s.document(in); !errors.Is(err, ErrInvalid) {
|
||||
t.Fatal("invalid UTF-8 was silently rewritten")
|
||||
}
|
||||
for _, test := range []struct {
|
||||
err error
|
||||
state, code string
|
||||
}{
|
||||
{context.DeadlineExceeded, "PENDING", "UNCONFIRMED"},
|
||||
{&orbit.APIError{StatusCode: 503, Code: "UNAVAILABLE"}, "PENDING", "UNCONFIRMED"},
|
||||
{&orbit.APIError{StatusCode: 429, RetryAfter: 30 * time.Second}, "PENDING", "BACKPRESSURE"},
|
||||
{&orbit.APIError{StatusCode: 403}, "REVIEW", "AUTHORIZATION"},
|
||||
{&orbit.APIError{StatusCode: 409, Code: "IDEMPOTENCY_CONFLICT"}, "REVIEW", "IDEMPOTENCY_CONFLICT"},
|
||||
{&orbit.HTTPError{StatusCode: 302}, "REVIEW", "HTTP_REJECTED"},
|
||||
{&orbit.HTTPError{StatusCode: 502}, "PENDING", "UNCONFIRMED"},
|
||||
} {
|
||||
state, code, delay := classify(test.err, 100)
|
||||
if state != test.state || code != test.code || delay < time.Second || delay > time.Hour {
|
||||
t.Fatal(state, code, delay)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user