go.temporal.io/server@v1.23.0/common/persistence/visibility/store/standard/visibility_store.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2021 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 standard
    26  
    27  import (
    28  	"context"
    29  	"encoding/json"
    30  	"fmt"
    31  	"reflect"
    32  
    33  	enumspb "go.temporal.io/api/enums/v1"
    34  
    35  	"go.temporal.io/server/common/persistence/visibility/manager"
    36  	"go.temporal.io/server/common/persistence/visibility/store"
    37  	"go.temporal.io/server/common/searchattribute"
    38  )
    39  
    40  type (
    41  	standardStore struct {
    42  		store                          store.VisibilityStore
    43  		searchAttributesProvider       searchattribute.Provider
    44  		searchAttributesMapperProvider searchattribute.MapperProvider
    45  	}
    46  
    47  	// We wrap the token with a boolean to indicate if it is from list open workflows or list closed workflows,
    48  	// so we know where to continue from for the next call.
    49  	nextPageToken struct {
    50  		ForOpenWorkflows bool `json:"isOpen"`
    51  		Token            []byte
    52  	}
    53  
    54  	listRequest interface {
    55  		OverrideToken(token []byte)
    56  		GetToken() []byte
    57  		OverridePageSize(pageSize int)
    58  		GetPageSize() int
    59  	}
    60  )
    61  
    62  var _ store.VisibilityStore = (*standardStore)(nil)
    63  var _ listRequest = (*manager.ListWorkflowExecutionsRequest)(nil)
    64  
    65  func NewVisibilityStore(
    66  	visibilityStore store.VisibilityStore,
    67  	searchAttributesProvider searchattribute.Provider,
    68  	searchAttributesMapperProvider searchattribute.MapperProvider,
    69  ) store.VisibilityStore {
    70  	return &standardStore{
    71  		store:                          visibilityStore,
    72  		searchAttributesProvider:       searchAttributesProvider,
    73  		searchAttributesMapperProvider: searchAttributesMapperProvider,
    74  	}
    75  }
    76  
    77  func (s *standardStore) Close() {
    78  	s.store.Close()
    79  }
    80  
    81  func (s *standardStore) GetName() string {
    82  	return s.store.GetName()
    83  }
    84  
    85  func (s *standardStore) GetIndexName() string {
    86  	// GetIndexName is used to get cluster metadata, which in verstions < v1.20
    87  	// were stored in an empty string key.
    88  	return ""
    89  }
    90  
    91  func (s *standardStore) ValidateCustomSearchAttributes(
    92  	searchAttributes map[string]any,
    93  ) (map[string]any, error) {
    94  	return searchAttributes, nil
    95  }
    96  
    97  func (s *standardStore) RecordWorkflowExecutionStarted(
    98  	ctx context.Context,
    99  	request *store.InternalRecordWorkflowExecutionStartedRequest,
   100  ) error {
   101  	return s.store.RecordWorkflowExecutionStarted(ctx, request)
   102  }
   103  
   104  func (s *standardStore) RecordWorkflowExecutionClosed(
   105  	ctx context.Context,
   106  	request *store.InternalRecordWorkflowExecutionClosedRequest,
   107  ) error {
   108  	return s.store.RecordWorkflowExecutionClosed(ctx, request)
   109  }
   110  
   111  func (s *standardStore) UpsertWorkflowExecution(
   112  	ctx context.Context,
   113  	request *store.InternalUpsertWorkflowExecutionRequest,
   114  ) error {
   115  	return s.store.UpsertWorkflowExecution(ctx, request)
   116  }
   117  
   118  func (s *standardStore) DeleteWorkflowExecution(
   119  	ctx context.Context,
   120  	request *manager.VisibilityDeleteWorkflowExecutionRequest,
   121  ) error {
   122  	return s.store.DeleteWorkflowExecution(ctx, request)
   123  }
   124  
   125  func (s *standardStore) ListOpenWorkflowExecutions(
   126  	ctx context.Context,
   127  	request *manager.ListWorkflowExecutionsRequest,
   128  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   129  	return s.store.ListOpenWorkflowExecutions(ctx, request)
   130  }
   131  
   132  func (s *standardStore) ListClosedWorkflowExecutions(
   133  	ctx context.Context,
   134  	request *manager.ListWorkflowExecutionsRequest,
   135  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   136  	return s.store.ListClosedWorkflowExecutions(ctx, request)
   137  }
   138  
   139  func (s *standardStore) ListOpenWorkflowExecutionsByType(
   140  	ctx context.Context,
   141  	request *manager.ListWorkflowExecutionsByTypeRequest,
   142  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   143  	return s.store.ListOpenWorkflowExecutionsByType(ctx, request)
   144  }
   145  
   146  func (s *standardStore) ListClosedWorkflowExecutionsByType(
   147  	ctx context.Context,
   148  	request *manager.ListWorkflowExecutionsByTypeRequest,
   149  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   150  	return s.store.ListClosedWorkflowExecutionsByType(ctx, request)
   151  }
   152  
   153  func (s *standardStore) ListOpenWorkflowExecutionsByWorkflowID(
   154  	ctx context.Context,
   155  	request *manager.ListWorkflowExecutionsByWorkflowIDRequest,
   156  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   157  	return s.store.ListOpenWorkflowExecutionsByWorkflowID(ctx, request)
   158  }
   159  
   160  func (s *standardStore) ListClosedWorkflowExecutionsByWorkflowID(
   161  	ctx context.Context,
   162  	request *manager.ListWorkflowExecutionsByWorkflowIDRequest,
   163  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   164  	return s.store.ListClosedWorkflowExecutionsByWorkflowID(ctx, request)
   165  }
   166  
   167  func (s *standardStore) ListClosedWorkflowExecutionsByStatus(
   168  	ctx context.Context,
   169  	request *manager.ListClosedWorkflowExecutionsByStatusRequest,
   170  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   171  	return s.store.ListClosedWorkflowExecutionsByStatus(ctx, request)
   172  }
   173  
   174  func (s *standardStore) ScanWorkflowExecutions(
   175  	ctx context.Context,
   176  	request *manager.ListWorkflowExecutionsRequestV2,
   177  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   178  	return s.store.ScanWorkflowExecutions(ctx, request)
   179  }
   180  
   181  func (s *standardStore) CountWorkflowExecutions(
   182  	ctx context.Context,
   183  	request *manager.CountWorkflowExecutionsRequest,
   184  ) (*manager.CountWorkflowExecutionsResponse, error) {
   185  	return s.store.CountWorkflowExecutions(ctx, request)
   186  }
   187  
   188  func (s *standardStore) GetWorkflowExecution(
   189  	ctx context.Context,
   190  	request *manager.GetWorkflowExecutionRequest,
   191  ) (*store.InternalGetWorkflowExecutionResponse, error) {
   192  	return s.store.GetWorkflowExecution(ctx, request)
   193  }
   194  
   195  func (s *standardStore) ListWorkflowExecutions(
   196  	ctx context.Context,
   197  	request *manager.ListWorkflowExecutionsRequestV2,
   198  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   199  	typeMap, err := s.searchAttributesProvider.GetSearchAttributes(s.GetIndexName(), false)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  
   204  	converter := newQueryConverter(request.Namespace, typeMap, s.searchAttributesMapperProvider)
   205  	filter, err := converter.GetFilter(request.Query)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  
   210  	baseReq := &manager.ListWorkflowExecutionsRequest{
   211  		NamespaceID:       request.NamespaceID,
   212  		Namespace:         request.Namespace,
   213  		PageSize:          request.PageSize,
   214  		NextPageToken:     request.NextPageToken,
   215  		EarliestStartTime: *filter.MinTime,
   216  		LatestStartTime:   *filter.MaxTime,
   217  	}
   218  
   219  	// Only a limited query patterns are supported due to the way we set up
   220  	// visibility tables in Cassandra.
   221  	// Check validation logic in query interceptor for details.
   222  	if filter.WorkflowID != nil {
   223  		request := &manager.ListWorkflowExecutionsByWorkflowIDRequest{
   224  			ListWorkflowExecutionsRequest: baseReq,
   225  			WorkflowID:                    *filter.WorkflowID,
   226  		}
   227  		return s.listWorkflowExecutionsHelper(
   228  			ctx,
   229  			request,
   230  			s.listOpenWorkflowExecutionsByWorkflowID,
   231  			s.listClosedWorkflowExecutionsByWorkflowID)
   232  	} else if filter.WorkflowTypeName != nil {
   233  		request := &manager.ListWorkflowExecutionsByTypeRequest{
   234  			ListWorkflowExecutionsRequest: baseReq,
   235  			WorkflowTypeName:              *filter.WorkflowTypeName,
   236  		}
   237  		return s.listWorkflowExecutionsHelper(
   238  			ctx,
   239  			request,
   240  			s.listOpenWorkflowExecutionsByType,
   241  			s.listClosedWorkflowExecutionsByType)
   242  	} else if filter.Status != int32(enumspb.WORKFLOW_EXECUTION_STATUS_UNSPECIFIED) {
   243  		if filter.Status == int32(enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING) {
   244  			return s.ListOpenWorkflowExecutions(ctx, baseReq)
   245  		} else {
   246  			request := &manager.ListClosedWorkflowExecutionsByStatusRequest{
   247  				ListWorkflowExecutionsRequest: baseReq,
   248  				Status:                        enumspb.WorkflowExecutionStatus(filter.Status),
   249  			}
   250  			return s.ListClosedWorkflowExecutionsByStatus(ctx, request)
   251  		}
   252  	} else {
   253  		return s.listWorkflowExecutionsHelper(
   254  			ctx,
   255  			baseReq,
   256  			s.listOpenWorkflowExecutions,
   257  			s.listClosedWorkflowExecutions)
   258  	}
   259  }
   260  
   261  func (s *standardStore) listWorkflowExecutionsHelper(
   262  	ctx context.Context,
   263  	request listRequest,
   264  	listOpenFunc func(ctx context.Context, request listRequest) (*store.InternalListWorkflowExecutionsResponse, error),
   265  	listCloseFunc func(ctx context.Context, request listRequest) (*store.InternalListWorkflowExecutionsResponse, error),
   266  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   267  
   268  	var token nextPageToken
   269  	if len(request.GetToken()) == 0 {
   270  		token = nextPageToken{
   271  			ForOpenWorkflows: true,
   272  		}
   273  	} else {
   274  		err := json.Unmarshal(request.GetToken(), &token)
   275  		if err != nil {
   276  			return nil, fmt.Errorf("invalid next page token: %v", err)
   277  		}
   278  		request.OverrideToken(token.Token)
   279  	}
   280  
   281  	resp := &store.InternalListWorkflowExecutionsResponse{}
   282  
   283  	if token.ForOpenWorkflows {
   284  		listOpenResp, err := listOpenFunc(ctx, request)
   285  		if err != nil {
   286  			return nil, err
   287  		}
   288  
   289  		if len(listOpenResp.Executions) > 0 {
   290  			request.OverridePageSize(request.GetPageSize() - len(listOpenResp.Executions))
   291  			resp.Executions = append(resp.Executions, listOpenResp.Executions...)
   292  		}
   293  
   294  		if request.GetPageSize() == 0 {
   295  			token.Token = listOpenResp.NextPageToken
   296  
   297  			token, err := json.Marshal(token)
   298  			if err != nil {
   299  				return nil, fmt.Errorf("failed to marshal next page token: %v", err)
   300  			}
   301  
   302  			resp.NextPageToken = token
   303  			return resp, nil
   304  		} else {
   305  			token.ForOpenWorkflows = false
   306  			request.OverrideToken(nil)
   307  		}
   308  	}
   309  
   310  	listCloseResp, err := listCloseFunc(ctx, request)
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  	resp.Executions = append(resp.Executions, listCloseResp.Executions...)
   315  
   316  	if listCloseResp.NextPageToken == nil {
   317  		resp.NextPageToken = nil
   318  	} else {
   319  		token.Token = listCloseResp.NextPageToken
   320  		token, err := json.Marshal(token)
   321  		if err != nil {
   322  			return nil, fmt.Errorf("failed to marshal next page token: %v", err)
   323  		}
   324  
   325  		resp.NextPageToken = token
   326  	}
   327  
   328  	return resp, nil
   329  }
   330  
   331  func (s *standardStore) listOpenWorkflowExecutionsByWorkflowID(
   332  	ctx context.Context,
   333  	request listRequest,
   334  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   335  	actualRequest, ok := request.(*manager.ListWorkflowExecutionsByWorkflowIDRequest)
   336  	if !ok {
   337  		panic(fmt.Errorf("wrong request type %v for listOpenWorkflowExecutionsByWorkflowID", reflect.TypeOf(request)))
   338  	}
   339  
   340  	return s.ListOpenWorkflowExecutionsByWorkflowID(ctx, actualRequest)
   341  }
   342  
   343  func (s *standardStore) listOpenWorkflowExecutionsByType(
   344  	ctx context.Context,
   345  	request listRequest,
   346  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   347  	actualRequest, ok := request.(*manager.ListWorkflowExecutionsByTypeRequest)
   348  	if !ok {
   349  		panic(fmt.Errorf("wrong request type %v for listOpenWorkflowExecutionsByType", reflect.TypeOf(request)))
   350  	}
   351  
   352  	return s.ListOpenWorkflowExecutionsByType(ctx, actualRequest)
   353  }
   354  
   355  func (s *standardStore) listOpenWorkflowExecutions(
   356  	ctx context.Context,
   357  	request listRequest,
   358  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   359  	actualRequest, ok := request.(*manager.ListWorkflowExecutionsRequest)
   360  	if !ok {
   361  		panic(fmt.Errorf("wrong request type %v for listOpenWorkflowExecutions", reflect.TypeOf(request)))
   362  	}
   363  
   364  	return s.ListOpenWorkflowExecutions(ctx, actualRequest)
   365  }
   366  
   367  func (s *standardStore) listClosedWorkflowExecutionsByWorkflowID(
   368  	ctx context.Context,
   369  	request listRequest,
   370  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   371  	actualRequest, ok := request.(*manager.ListWorkflowExecutionsByWorkflowIDRequest)
   372  	if !ok {
   373  		panic(fmt.Errorf("wrong request type %v for listClosedWorkflowExecutionsByWorkflowID", reflect.TypeOf(request)))
   374  	}
   375  
   376  	return s.ListClosedWorkflowExecutionsByWorkflowID(ctx, actualRequest)
   377  }
   378  
   379  func (s *standardStore) listClosedWorkflowExecutionsByType(
   380  	ctx context.Context,
   381  	request listRequest,
   382  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   383  	actualRequest, ok := request.(*manager.ListWorkflowExecutionsByTypeRequest)
   384  	if !ok {
   385  		panic(fmt.Errorf("wrong request type %v for listClosedWorkflowExecutionsByType", reflect.TypeOf(request)))
   386  	}
   387  
   388  	return s.ListClosedWorkflowExecutionsByType(ctx, actualRequest)
   389  }
   390  
   391  func (s *standardStore) listClosedWorkflowExecutions(
   392  	ctx context.Context,
   393  	request listRequest,
   394  ) (*store.InternalListWorkflowExecutionsResponse, error) {
   395  	actualRequest, ok := request.(*manager.ListWorkflowExecutionsRequest)
   396  	if !ok {
   397  		panic(fmt.Errorf("wrong request type %v for listClosedWorkflowExecutions", reflect.TypeOf(request)))
   398  	}
   399  
   400  	return s.ListClosedWorkflowExecutions(ctx, actualRequest)
   401  }