feat: refactor to ymsctl & yms-daemon
This commit is contained in:
@@ -18,6 +18,13 @@ type Transaction struct {
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// ListFilter limits the history query used by the ymsctl list command.
|
||||
type ListFilter struct {
|
||||
Limit int
|
||||
Service string
|
||||
State State
|
||||
}
|
||||
|
||||
// CreateRequest 包含创建事务所需的不可变请求信息。
|
||||
type CreateRequest struct {
|
||||
ID string
|
||||
|
||||
@@ -335,6 +335,56 @@ func (s *Store) ActiveTransaction(ctx context.Context) (Transaction, error) {
|
||||
return getActiveTransaction(ctx, s.db)
|
||||
}
|
||||
|
||||
// ListRecent returns committed, rolled-back, failed, and in-progress transactions
|
||||
// in reverse creation order. Filters are exact values and never inferred.
|
||||
func (s *Store) ListRecent(ctx context.Context, filter ListFilter) ([]Transaction, error) {
|
||||
if filter.Limit <= 0 || filter.Limit > 1000 {
|
||||
return nil, errors.New("transaction history limit must be between 1 and 1000")
|
||||
}
|
||||
query := `SELECT id, idempotency_key, source, service, request_json, state, version, created_at, updated_at FROM transactions WHERE 1=1`
|
||||
args := make([]any, 0, 3)
|
||||
if filter.Service != "" {
|
||||
query += " AND service = ?"
|
||||
args = append(args, filter.Service)
|
||||
}
|
||||
if filter.State != "" {
|
||||
query += " AND state = ?"
|
||||
args = append(args, string(filter.State))
|
||||
}
|
||||
query += " ORDER BY created_at DESC, id DESC LIMIT ?"
|
||||
args = append(args, filter.Limit)
|
||||
rows, err := s.db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list transaction history: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
result := make([]Transaction, 0, filter.Limit)
|
||||
for rows.Next() {
|
||||
var item Transaction
|
||||
var state string
|
||||
var requestJSON string
|
||||
var createdAt, updatedAt string
|
||||
if err := rows.Scan(&item.ID, &item.IdempotencyKey, &item.Source, &item.Service, &requestJSON, &state, &item.Version, &createdAt, &updatedAt); err != nil {
|
||||
return nil, fmt.Errorf("scan transaction history: %w", err)
|
||||
}
|
||||
item.Request = json.RawMessage(requestJSON)
|
||||
item.State = State(state)
|
||||
item.CreatedAt, err = time.Parse(time.RFC3339Nano, createdAt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse transaction history creation time: %w", err)
|
||||
}
|
||||
item.UpdatedAt, err = time.Parse(time.RFC3339Nano, updatedAt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse transaction history update time: %w", err)
|
||||
}
|
||||
result = append(result, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("iterate transaction history: %w", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Transition 校验并原子提交状态变化及其恢复事件。
|
||||
func (s *Store) Transition(ctx context.Context, id string, next State, message string) (Transaction, error) {
|
||||
if !next.Valid() {
|
||||
|
||||
@@ -105,6 +105,26 @@ func TestStoreMigratesVersionOneAndCommitsBackendContainerDeployment(t *testing.
|
||||
}
|
||||
}
|
||||
|
||||
func TestListRecentScansSQLiteRequestTextAsRawJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
store := openTestStore(t)
|
||||
record, _, err := store.CreateTransaction(ctx, CreateRequest{
|
||||
ID: "list-transaction", IdempotencyKey: "list-idempotency", Source: "test", Service: "backend",
|
||||
Request: json.RawMessage(`{"inputType":"native-jar"}`),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create list transaction: %v", err)
|
||||
}
|
||||
items, err := store.ListRecent(ctx, ListFilter{Limit: 20})
|
||||
if err != nil {
|
||||
t.Fatalf("list transactions: %v", err)
|
||||
}
|
||||
if len(items) != 1 || items[0].ID != record.ID || string(items[0].Request) != `{"inputType":"native-jar"}` {
|
||||
t.Fatalf("unexpected listed transaction: %+v", items)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackendContainerDeploymentCommitRequiresDrainingTransaction(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
|
||||
Reference in New Issue
Block a user