go.temporal.io/server@v1.23.0/common/worker_versioning/worker_versioning.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package worker_versioning 26 27 import ( 28 "context" 29 "fmt" 30 31 "github.com/temporalio/sqlparser" 32 commonpb "go.temporal.io/api/common/v1" 33 "google.golang.org/protobuf/types/known/emptypb" 34 35 persistencespb "go.temporal.io/server/api/persistence/v1" 36 taskqueuespb "go.temporal.io/server/api/taskqueue/v1" 37 "go.temporal.io/server/common" 38 "go.temporal.io/server/common/namespace" 39 "go.temporal.io/server/common/persistence/visibility/manager" 40 "go.temporal.io/server/common/searchattribute" 41 ) 42 43 const ( 44 buildIdSearchAttributePrefixVersioned = "versioned" 45 buildIdSearchAttributePrefixUnversioned = "unversioned" 46 BuildIdSearchAttributeDelimiter = ":" 47 // UnversionedSearchAttribute is the sentinel value used to mark all unversioned workflows 48 UnversionedSearchAttribute = buildIdSearchAttributePrefixUnversioned 49 ) 50 51 // VersionedBuildIdSearchAttribute returns the search attribute value for an unversioned build id 52 func VersionedBuildIdSearchAttribute(buildId string) string { 53 return buildIdSearchAttributePrefixVersioned + BuildIdSearchAttributeDelimiter + buildId 54 } 55 56 // VersionedBuildIdSearchAttribute returns the search attribute value for an versioned build id 57 func UnversionedBuildIdSearchAttribute(buildId string) string { 58 return buildIdSearchAttributePrefixUnversioned + BuildIdSearchAttributeDelimiter + buildId 59 } 60 61 // VersionStampToBuildIdSearchAttribute returns the search attribute value for a version stamp 62 func VersionStampToBuildIdSearchAttribute(stamp *commonpb.WorkerVersionStamp) string { 63 if stamp.GetBuildId() == "" { 64 return UnversionedSearchAttribute 65 } 66 if stamp.UseVersioning { 67 return VersionedBuildIdSearchAttribute(stamp.BuildId) 68 } 69 return UnversionedBuildIdSearchAttribute(stamp.BuildId) 70 } 71 72 // FindBuildId finds a build id in the version data's sets, returning (set index, index within that set). 73 // Returns -1, -1 if not found. 74 func FindBuildId(versioningData *persistencespb.VersioningData, buildId string) (setIndex, indexInSet int) { 75 versionSets := versioningData.GetVersionSets() 76 for sidx, set := range versionSets { 77 for bidx, id := range set.GetBuildIds() { 78 if buildId == id.Id { 79 return sidx, bidx 80 } 81 } 82 } 83 return -1, -1 84 } 85 86 func WorkflowsExistForBuildId(ctx context.Context, visibilityManager manager.VisibilityManager, ns *namespace.Namespace, taskQueue, buildId string) (bool, error) { 87 escapedTaskQueue := sqlparser.String(sqlparser.NewStrVal([]byte(taskQueue))) 88 escapedBuildId := sqlparser.String(sqlparser.NewStrVal([]byte(VersionedBuildIdSearchAttribute(buildId)))) 89 query := fmt.Sprintf("%s = %s AND %s = %s", searchattribute.TaskQueue, escapedTaskQueue, searchattribute.BuildIds, escapedBuildId) 90 91 response, err := visibilityManager.CountWorkflowExecutions(ctx, &manager.CountWorkflowExecutionsRequest{ 92 NamespaceID: ns.ID(), 93 Namespace: ns.Name(), 94 Query: query, 95 }) 96 if err != nil { 97 return false, err 98 } 99 return response.Count > 0, nil 100 } 101 102 // StampIfUsingVersioning returns the given WorkerVersionStamp if it is using versioning, 103 // otherwise returns nil. 104 func StampIfUsingVersioning(stamp *commonpb.WorkerVersionStamp) *commonpb.WorkerVersionStamp { 105 if stamp.GetUseVersioning() { 106 return stamp 107 } 108 return nil 109 } 110 111 func MakeDirectiveForWorkflowTask( 112 stamp *commonpb.WorkerVersionStamp, 113 lastWorkflowTaskStartedEventID int64, 114 ) *taskqueuespb.TaskVersionDirective { 115 var directive taskqueuespb.TaskVersionDirective 116 if id := StampIfUsingVersioning(stamp).GetBuildId(); id != "" { 117 directive.Value = &taskqueuespb.TaskVersionDirective_BuildId{BuildId: id} 118 } else if lastWorkflowTaskStartedEventID == common.EmptyEventID { 119 // first workflow task 120 directive.Value = &taskqueuespb.TaskVersionDirective_UseDefault{UseDefault: &emptypb.Empty{}} 121 } 122 // else: unversioned queue 123 return &directive 124 } 125 126 func MakeDirectiveForActivityTask( 127 stamp *commonpb.WorkerVersionStamp, 128 useCompatibleVersion bool, 129 ) *taskqueuespb.TaskVersionDirective { 130 var directive taskqueuespb.TaskVersionDirective 131 if !useCompatibleVersion { 132 directive.Value = &taskqueuespb.TaskVersionDirective_UseDefault{UseDefault: &emptypb.Empty{}} 133 } else if id := StampIfUsingVersioning(stamp).GetBuildId(); id != "" { 134 directive.Value = &taskqueuespb.TaskVersionDirective_BuildId{BuildId: id} 135 } 136 // else: unversioned queue 137 return &directive 138 }