mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-10 10:26:46 +08:00
perf(db): generate task message IDs as UUIDv7 (#7220)
Co-authored-by: Sol-Boy <[email protected]> Co-authored-by: multica-agent <[email protected]>
This commit is contained in:
co-authored by
Sol-Boy
multica-agent
parent
f9b7bf52ea
commit
ea07a29138
@@ -16,6 +16,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/multica-ai/multica/server/internal/analytics"
|
||||
@@ -4381,7 +4382,18 @@ func (h *Handler) ReportTaskMessages(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
for _, msg := range req.Messages {
|
||||
messageIDs := make([]pgtype.UUID, len(req.Messages))
|
||||
for i := range messageIDs {
|
||||
id, err := uuid.NewV7()
|
||||
if err != nil {
|
||||
slog.Error("failed to generate task message id", "task_id", taskID, "error", err)
|
||||
writeError(w, http.StatusInternalServerError, "failed to persist task message")
|
||||
return
|
||||
}
|
||||
messageIDs[i] = pgtype.UUID{Bytes: [16]byte(id), Valid: true}
|
||||
}
|
||||
|
||||
for i, msg := range req.Messages {
|
||||
// Redact sensitive information before persisting or broadcasting.
|
||||
msg.Content = redact.Text(msg.Content)
|
||||
msg.Output = redact.Text(msg.Output)
|
||||
@@ -4409,6 +4421,7 @@ func (h *Handler) ReportTaskMessages(w http.ResponseWriter, r *http.Request) {
|
||||
inputJSON, _ = json.Marshal(msg.Input)
|
||||
}
|
||||
created, createErr := h.Queries.CreateTaskMessage(r.Context(), db.CreateTaskMessageParams{
|
||||
ID: messageIDs[i],
|
||||
TaskID: parseUUID(taskID),
|
||||
Seq: int32(msg.Seq),
|
||||
Type: msg.Type,
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/multica-ai/multica/server/internal/util"
|
||||
db "github.com/multica-ai/multica/server/pkg/db/generated"
|
||||
)
|
||||
@@ -198,6 +199,41 @@ func TestReportTaskMessagesCallbackWithNULSucceeds(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReportTaskMessagesCreatesUUIDv7(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
_, taskID := seedNULTask(t, "uuidv7-messages-agent")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := daemonTaskRequest(t, "/api/daemon/tasks/"+taskID+"/messages", taskID, map[string]any{
|
||||
"messages": []any{
|
||||
map[string]any{
|
||||
"seq": 1,
|
||||
"type": "text",
|
||||
"content": "UUIDv7 task message",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
testHandler.ReportTaskMessages(w, req)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("ReportTaskMessages returned %d, want 200: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
var rawID string
|
||||
if err := testPool.QueryRow(ctx, `
|
||||
SELECT id::text
|
||||
FROM task_message WHERE task_id = $1 AND seq = 1`, taskID).Scan(&rawID); err != nil {
|
||||
t.Fatalf("read persisted task message id: %v", err)
|
||||
}
|
||||
messageID, err := uuid.Parse(rawID)
|
||||
if err != nil {
|
||||
t.Fatalf("parse task message id %q: %v", rawID, err)
|
||||
}
|
||||
if got := messageID.Version(); got != 7 {
|
||||
t.Fatalf("task message UUID version = %d, want 7", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestPostgresRejectsUnsanitizedTaskPayloads is the control for both tests
|
||||
// above: it proves the database really does refuse these payloads, so the
|
||||
// handler tests are demonstrating a fix rather than a no-op. If PostgreSQL ever
|
||||
|
||||
@@ -12,12 +12,13 @@ import (
|
||||
)
|
||||
|
||||
const createTaskMessage = `-- name: CreateTaskMessage :one
|
||||
INSERT INTO task_message (task_id, seq, type, tool, content, input, output)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
INSERT INTO task_message (id, task_id, seq, type, tool, content, input, output)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
RETURNING id, task_id, seq, type, tool, content, input, output, created_at
|
||||
`
|
||||
|
||||
type CreateTaskMessageParams struct {
|
||||
ID pgtype.UUID `json:"id"`
|
||||
TaskID pgtype.UUID `json:"task_id"`
|
||||
Seq int32 `json:"seq"`
|
||||
Type string `json:"type"`
|
||||
@@ -29,6 +30,7 @@ type CreateTaskMessageParams struct {
|
||||
|
||||
func (q *Queries) CreateTaskMessage(ctx context.Context, arg CreateTaskMessageParams) (TaskMessage, error) {
|
||||
row := q.db.QueryRow(ctx, createTaskMessage,
|
||||
arg.ID,
|
||||
arg.TaskID,
|
||||
arg.Seq,
|
||||
arg.Type,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- name: CreateTaskMessage :one
|
||||
INSERT INTO task_message (task_id, seq, type, tool, content, input, output)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
INSERT INTO task_message (id, task_id, seq, type, tool, content, input, output)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
RETURNING *;
|
||||
|
||||
-- name: ListTaskMessages :many
|
||||
|
||||
Reference in New Issue
Block a user