From 270ca99227a41c4fe826ba15bfdf9502da3f1b54 Mon Sep 17 00:00:00 2001 From: Tim Deeb-Swihart Date: Wed, 4 Dec 2024 14:56:51 -0500 Subject: [PATCH 1/4] Change RunIDs to use UUIDv7 --- service/history/api/startworkflow/api.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/service/history/api/startworkflow/api.go b/service/history/api/startworkflow/api.go index 721e4637e4..f4d4c89296 100644 --- a/service/history/api/startworkflow/api.go +++ b/service/history/api/startworkflow/api.go @@ -27,6 +27,7 @@ package startworkflow import ( "context" "errors" + "fmt" "time" "github.com/google/uuid" @@ -249,7 +250,11 @@ func (s *Starter) lockCurrentWorkflowExecution( // prepareNewWorkflow creates a new workflow context, and closes its mutable state transaction as snapshot. // It returns the creationContext which can later be used to insert into the executions table. func (s *Starter) prepareNewWorkflow(workflowID string) (*creationParams, error) { - runID := uuid.NewString() + runUUID, err := uuid.NewV7() + if err != nil { + return nil, fmt.Errorf("failed to generate run id: %w", err) + } + runID := runUUID.String() mutableState, err := api.NewWorkflowWithSignal( s.shardContext, s.namespace, From 47b31cd77f76dcfdde8db55ffdfe9300b32062dc Mon Sep 17 00:00:00 2001 From: Tim Deeb-Swihart Date: Wed, 4 Dec 2024 16:50:33 -0500 Subject: [PATCH 2/4] I missed a spot --- service/history/api/startworkflow/api.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/service/history/api/startworkflow/api.go b/service/history/api/startworkflow/api.go index f4d4c89296..2d7d9aa8eb 100644 --- a/service/history/api/startworkflow/api.go +++ b/service/history/api/startworkflow/api.go @@ -408,7 +408,11 @@ func (s *Starter) resolveDuplicateWorkflowID( // Using a new RunID here to simplify locking: MultiOperation, that re-uses the Starter, is creating // a locked workflow context for each new workflow. Using a fresh RunID prevents a deadlock with the // previously created workflow context. - newRunID := uuid.NewString() + newRunUUID, err := uuid.NewV7() + if err != nil { + return nil, StartErr, fmt.Errorf("failed to generate run id: %w", err) + } + newRunID := newRunUUID.String() currentExecutionUpdateAction, err := api.ResolveDuplicateWorkflowID( s.shardContext, From 3a8e5b308f5495af5177f5c523c478d5b1a0a24b Mon Sep 17 00:00:00 2001 From: Tim Deeb-Swihart Date: Thu, 5 Dec 2024 10:44:52 -0500 Subject: [PATCH 3/4] Use uuidv7 by default for primitives.UUID --- common/primitives/uuid.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common/primitives/uuid.go b/common/primitives/uuid.go index 733472e8ce..18e34a4499 100644 --- a/common/primitives/uuid.go +++ b/common/primitives/uuid.go @@ -29,7 +29,6 @@ import ( "encoding/hex" guuid "github.com/google/uuid" - "github.com/pborman/uuid" ) // UUID represents a 16-byte universally unique identifier @@ -93,7 +92,12 @@ func ValidateUUID(s string) (string, error) { // NewUUID generates a new random UUID func NewUUID() UUID { - return UUID(uuid.NewRandom()) + u, err := guuid.NewV7() + if err != nil { + // Should never happen, but this matches the behavior of pborman/uuid.NewRandom + return nil + } + return u[:] } // Downcast returns the UUID as a byte slice. This is necessary when passing to type sensitive interfaces such as cql. From dbae65630ff014aee5abcd69b2ca5e3d305c4ecc Mon Sep 17 00:00:00 2001 From: Tim Deeb-Swihart Date: Thu, 5 Dec 2024 22:02:38 -0500 Subject: [PATCH 4/4] Use primitives.NewUUID --- service/history/api/startworkflow/api.go | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/service/history/api/startworkflow/api.go b/service/history/api/startworkflow/api.go index 2d7d9aa8eb..94f9ae4722 100644 --- a/service/history/api/startworkflow/api.go +++ b/service/history/api/startworkflow/api.go @@ -27,10 +27,8 @@ package startworkflow import ( "context" "errors" - "fmt" "time" - "github.com/google/uuid" commonpb "go.temporal.io/api/common/v1" enumspb "go.temporal.io/api/enums/v1" historypb "go.temporal.io/api/history/v1" @@ -45,6 +43,7 @@ import ( "go.temporal.io/server/common/namespace" "go.temporal.io/server/common/persistence" "go.temporal.io/server/common/persistence/visibility/manager" + "go.temporal.io/server/common/primitives" "go.temporal.io/server/common/tasktoken" "go.temporal.io/server/service/history/api" "go.temporal.io/server/service/history/consts" @@ -250,11 +249,7 @@ func (s *Starter) lockCurrentWorkflowExecution( // prepareNewWorkflow creates a new workflow context, and closes its mutable state transaction as snapshot. // It returns the creationContext which can later be used to insert into the executions table. func (s *Starter) prepareNewWorkflow(workflowID string) (*creationParams, error) { - runUUID, err := uuid.NewV7() - if err != nil { - return nil, fmt.Errorf("failed to generate run id: %w", err) - } - runID := runUUID.String() + runID := primitives.NewUUID().String() mutableState, err := api.NewWorkflowWithSignal( s.shardContext, s.namespace, @@ -408,11 +403,7 @@ func (s *Starter) resolveDuplicateWorkflowID( // Using a new RunID here to simplify locking: MultiOperation, that re-uses the Starter, is creating // a locked workflow context for each new workflow. Using a fresh RunID prevents a deadlock with the // previously created workflow context. - newRunUUID, err := uuid.NewV7() - if err != nil { - return nil, StartErr, fmt.Errorf("failed to generate run id: %w", err) - } - newRunID := newRunUUID.String() + newRunID := primitives.NewUUID().String() currentExecutionUpdateAction, err := api.ResolveDuplicateWorkflowID( s.shardContext,