go.temporal.io/server@v1.23.0/common/persistence/visibility/visibility_manager_impl.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 visibility
    26  
    27  import (
    28  	"context"
    29  	"fmt"
    30  	"time"
    31  
    32  	commonpb "go.temporal.io/api/common/v1"
    33  	enumspb "go.temporal.io/api/enums/v1"
    34  	"go.temporal.io/api/serviceerror"
    35  	workflowpb "go.temporal.io/api/workflow/v1"
    36  	"google.golang.org/protobuf/proto"
    37  	"google.golang.org/protobuf/types/known/timestamppb"
    38  
    39  	"go.temporal.io/server/common/log"
    40  	"go.temporal.io/server/common/namespace"
    41  	"go.temporal.io/server/common/persistence/visibility/manager"
    42  	"go.temporal.io/server/common/persistence/visibility/store"
    43  	"go.temporal.io/server/common/searchattribute"
    44  )
    45  
    46  type (
    47  	// visibilityManagerImpl is responsible for:
    48  	//  - convert request (serialized some fields),
    49  	//  - call underlying store (standard or advanced),
    50  	//  - convert response.
    51  	visibilityManagerImpl struct {
    52  		store  store.VisibilityStore
    53  		logger log.Logger
    54  	}
    55  )
    56  
    57  const (
    58  	// MemoEncoding is default encoding for visibility memo.
    59  	MemoEncoding = enumspb.ENCODING_TYPE_PROTO3
    60  )
    61  
    62  var _ manager.VisibilityManager = (*visibilityManagerImpl)(nil)
    63  
    64  func newVisibilityManagerImpl(
    65  	store store.VisibilityStore,
    66  	logger log.Logger,
    67  ) *visibilityManagerImpl {
    68  	return &visibilityManagerImpl{
    69  		store:  store,
    70  		logger: logger,
    71  	}
    72  }
    73  
    74  func (p *visibilityManagerImpl) Close() {
    75  	p.store.Close()
    76  }
    77  
    78  func (p *visibilityManagerImpl) GetReadStoreName(_ namespace.Name) string {
    79  	return p.store.GetName()
    80  }
    81  
    82  func (p *visibilityManagerImpl) GetStoreNames() []string {
    83  	return []string{p.store.GetName()}
    84  }
    85  
    86  func (p *visibilityManagerImpl) HasStoreName(stName string) bool {
    87  	return p.store.GetName() == stName
    88  }
    89  
    90  func (p *visibilityManagerImpl) GetIndexName() string {
    91  	return p.store.GetIndexName()
    92  }
    93  
    94  func (p *visibilityManagerImpl) ValidateCustomSearchAttributes(
    95  	searchAttributes map[string]any,
    96  ) (map[string]any, error) {
    97  	return p.store.ValidateCustomSearchAttributes(searchAttributes)
    98  }
    99  
   100  func (p *visibilityManagerImpl) RecordWorkflowExecutionStarted(
   101  	ctx context.Context,
   102  	request *manager.RecordWorkflowExecutionStartedRequest,
   103  ) error {
   104  	requestBase, err := p.newInternalVisibilityRequestBase(request.VisibilityRequestBase)
   105  	if err != nil {
   106  		return err
   107  	}
   108  	req := &store.InternalRecordWorkflowExecutionStartedRequest{
   109  		InternalVisibilityRequestBase: requestBase,
   110  	}
   111  	return p.store.RecordWorkflowExecutionStarted(ctx, req)
   112  }
   113  
   114  func (p *visibilityManagerImpl) RecordWorkflowExecutionClosed(
   115  	ctx context.Context,
   116  	request *manager.RecordWorkflowExecutionClosedRequest,
   117  ) error {
   118  	requestBase, err := p.newInternalVisibilityRequestBase(request.VisibilityRequestBase)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	req := &store.InternalRecordWorkflowExecutionClosedRequest{
   123  		InternalVisibilityRequestBase: requestBase,
   124  		CloseTime:                     request.CloseTime,
   125  		HistoryLength:                 request.HistoryLength,
   126  		HistorySizeBytes:              request.HistorySizeBytes,
   127  		ExecutionDuration:             request.CloseTime.Sub(request.ExecutionTime),
   128  		StateTransitionCount:          request.StateTransitionCount,
   129  	}
   130  	return p.store.RecordWorkflowExecutionClosed(ctx, req)
   131  }
   132  
   133  func (p *visibilityManagerImpl) UpsertWorkflowExecution(
   134  	ctx context.Context,
   135  	request *manager.UpsertWorkflowExecutionRequest,
   136  ) error {
   137  	requestBase, err := p.newInternalVisibilityRequestBase(request.VisibilityRequestBase)
   138  	if err != nil {
   139  		return err
   140  	}
   141  	req := &store.InternalUpsertWorkflowExecutionRequest{
   142  		InternalVisibilityRequestBase: requestBase,
   143  	}
   144  	return p.store.UpsertWorkflowExecution(ctx, req)
   145  }
   146  
   147  func (p *visibilityManagerImpl) DeleteWorkflowExecution(
   148  	ctx context.Context,
   149  	request *manager.VisibilityDeleteWorkflowExecutionRequest,
   150  ) error {
   151  	return p.store.DeleteWorkflowExecution(ctx, request)
   152  }
   153  
   154  func (p *visibilityManagerImpl) ListOpenWorkflowExecutions(
   155  	ctx context.Context,
   156  	request *manager.ListWorkflowExecutionsRequest,
   157  ) (*manager.ListWorkflowExecutionsResponse, error) {
   158  	response, err := p.store.ListOpenWorkflowExecutions(ctx, request)
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  	return p.convertInternalListResponse(response)
   163  }
   164  
   165  func (p *visibilityManagerImpl) ListClosedWorkflowExecutions(
   166  	ctx context.Context,
   167  	request *manager.ListWorkflowExecutionsRequest,
   168  ) (*manager.ListWorkflowExecutionsResponse, error) {
   169  	response, err := p.store.ListClosedWorkflowExecutions(ctx, request)
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  
   174  	return p.convertInternalListResponse(response)
   175  }
   176  
   177  func (p *visibilityManagerImpl) ListOpenWorkflowExecutionsByType(
   178  	ctx context.Context,
   179  	request *manager.ListWorkflowExecutionsByTypeRequest,
   180  ) (*manager.ListWorkflowExecutionsResponse, error) {
   181  	response, err := p.store.ListOpenWorkflowExecutionsByType(ctx, request)
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  
   186  	return p.convertInternalListResponse(response)
   187  }
   188  
   189  func (p *visibilityManagerImpl) ListClosedWorkflowExecutionsByType(
   190  	ctx context.Context,
   191  	request *manager.ListWorkflowExecutionsByTypeRequest,
   192  ) (*manager.ListWorkflowExecutionsResponse, error) {
   193  	response, err := p.store.ListClosedWorkflowExecutionsByType(ctx, request)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  
   198  	return p.convertInternalListResponse(response)
   199  }
   200  
   201  func (p *visibilityManagerImpl) ListOpenWorkflowExecutionsByWorkflowID(
   202  	ctx context.Context,
   203  	request *manager.ListWorkflowExecutionsByWorkflowIDRequest,
   204  ) (*manager.ListWorkflowExecutionsResponse, error) {
   205  	response, err := p.store.ListOpenWorkflowExecutionsByWorkflowID(ctx, request)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  
   210  	return p.convertInternalListResponse(response)
   211  }
   212  
   213  func (p *visibilityManagerImpl) ListClosedWorkflowExecutionsByWorkflowID(
   214  	ctx context.Context,
   215  	request *manager.ListWorkflowExecutionsByWorkflowIDRequest,
   216  ) (*manager.ListWorkflowExecutionsResponse, error) {
   217  	response, err := p.store.ListClosedWorkflowExecutionsByWorkflowID(ctx, request)
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  
   222  	return p.convertInternalListResponse(response)
   223  }
   224  
   225  func (p *visibilityManagerImpl) ListClosedWorkflowExecutionsByStatus(
   226  	ctx context.Context,
   227  	request *manager.ListClosedWorkflowExecutionsByStatusRequest,
   228  ) (*manager.ListWorkflowExecutionsResponse, error) {
   229  	response, err := p.store.ListClosedWorkflowExecutionsByStatus(ctx, request)
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  
   234  	return p.convertInternalListResponse(response)
   235  }
   236  
   237  func (p *visibilityManagerImpl) ListWorkflowExecutions(
   238  	ctx context.Context,
   239  	request *manager.ListWorkflowExecutionsRequestV2,
   240  ) (*manager.ListWorkflowExecutionsResponse, error) {
   241  	response, err := p.store.ListWorkflowExecutions(ctx, request)
   242  	if err != nil {
   243  		return nil, err
   244  	}
   245  
   246  	return p.convertInternalListResponse(response)
   247  }
   248  
   249  func (p *visibilityManagerImpl) ScanWorkflowExecutions(
   250  	ctx context.Context,
   251  	request *manager.ListWorkflowExecutionsRequestV2,
   252  ) (*manager.ListWorkflowExecutionsResponse, error) {
   253  	response, err := p.store.ScanWorkflowExecutions(ctx, request)
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  
   258  	return p.convertInternalListResponse(response)
   259  }
   260  
   261  func (p *visibilityManagerImpl) CountWorkflowExecutions(
   262  	ctx context.Context,
   263  	request *manager.CountWorkflowExecutionsRequest,
   264  ) (*manager.CountWorkflowExecutionsResponse, error) {
   265  	response, err := p.store.CountWorkflowExecutions(ctx, request)
   266  	if err != nil {
   267  		return nil, err
   268  	}
   269  
   270  	return response, err
   271  }
   272  
   273  func (p *visibilityManagerImpl) GetWorkflowExecution(
   274  	ctx context.Context,
   275  	request *manager.GetWorkflowExecutionRequest,
   276  ) (*manager.GetWorkflowExecutionResponse, error) {
   277  	response, err := p.store.GetWorkflowExecution(ctx, request)
   278  	if err != nil {
   279  		return nil, err
   280  	}
   281  	execution, err := p.convertInternalWorkflowExecutionInfo(response.Execution)
   282  	if err != nil {
   283  		return nil, err
   284  	}
   285  	return &manager.GetWorkflowExecutionResponse{Execution: execution}, err
   286  }
   287  
   288  func (p *visibilityManagerImpl) newInternalVisibilityRequestBase(
   289  	request *manager.VisibilityRequestBase,
   290  ) (*store.InternalVisibilityRequestBase, error) {
   291  	if request == nil {
   292  		return nil, nil
   293  	}
   294  	memoBlob, err := p.serializeMemo(request.Memo)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  
   299  	var searchAttrs *commonpb.SearchAttributes
   300  	if len(request.SearchAttributes.GetIndexedFields()) > 0 {
   301  		// Remove any system search attribute from the map.
   302  		// This is necessary because the validation can supress errors when trying
   303  		// to set a value on a system search attribute.
   304  		searchAttrs = &commonpb.SearchAttributes{
   305  			IndexedFields: make(map[string]*commonpb.Payload),
   306  		}
   307  		for key, value := range request.SearchAttributes.IndexedFields {
   308  			if !searchattribute.IsSystem(key) {
   309  				searchAttrs.IndexedFields[key] = value
   310  			}
   311  		}
   312  	}
   313  
   314  	var (
   315  		parentWorkflowID *string
   316  		parentRunID      *string
   317  	)
   318  	if request.ParentExecution != nil {
   319  		parentWorkflowID = &request.ParentExecution.WorkflowId
   320  		parentRunID = &request.ParentExecution.RunId
   321  	}
   322  
   323  	return &store.InternalVisibilityRequestBase{
   324  		NamespaceID:      request.NamespaceID.String(),
   325  		WorkflowID:       request.Execution.GetWorkflowId(),
   326  		RunID:            request.Execution.GetRunId(),
   327  		WorkflowTypeName: request.WorkflowTypeName,
   328  		StartTime:        request.StartTime,
   329  		Status:           request.Status,
   330  		ExecutionTime:    request.ExecutionTime,
   331  		TaskID:           request.TaskID,
   332  		ShardID:          request.ShardID,
   333  		TaskQueue:        request.TaskQueue,
   334  		Memo:             memoBlob,
   335  		SearchAttributes: searchAttrs,
   336  		ParentWorkflowID: parentWorkflowID,
   337  		ParentRunID:      parentRunID,
   338  	}, nil
   339  }
   340  
   341  func (p *visibilityManagerImpl) convertInternalListResponse(
   342  	internalResponse *store.InternalListWorkflowExecutionsResponse,
   343  ) (*manager.ListWorkflowExecutionsResponse, error) {
   344  	if internalResponse == nil {
   345  		return nil, nil
   346  	}
   347  
   348  	resp := &manager.ListWorkflowExecutionsResponse{}
   349  	resp.Executions = make([]*workflowpb.WorkflowExecutionInfo, len(internalResponse.Executions))
   350  	for i, execution := range internalResponse.Executions {
   351  		var err error
   352  		resp.Executions[i], err = p.convertInternalWorkflowExecutionInfo(execution)
   353  		if err != nil {
   354  			return nil, err
   355  		}
   356  	}
   357  
   358  	resp.NextPageToken = internalResponse.NextPageToken
   359  	return resp, nil
   360  }
   361  
   362  func (p *visibilityManagerImpl) convertInternalWorkflowExecutionInfo(
   363  	internalExecution *store.InternalWorkflowExecutionInfo,
   364  ) (*workflowpb.WorkflowExecutionInfo, error) {
   365  	if internalExecution == nil {
   366  		return nil, nil
   367  	}
   368  	memo, err := p.deserializeMemo(internalExecution.Memo)
   369  	if err != nil {
   370  		return nil, err
   371  	}
   372  
   373  	executionInfo := &workflowpb.WorkflowExecutionInfo{
   374  		Execution: &commonpb.WorkflowExecution{
   375  			WorkflowId: internalExecution.WorkflowID,
   376  			RunId:      internalExecution.RunID,
   377  		},
   378  		Type: &commonpb.WorkflowType{
   379  			Name: internalExecution.TypeName,
   380  		},
   381  		StartTime:        timestamppb.New(internalExecution.StartTime),
   382  		ExecutionTime:    timestamppb.New(internalExecution.ExecutionTime),
   383  		Memo:             memo,
   384  		SearchAttributes: internalExecution.SearchAttributes,
   385  		TaskQueue:        internalExecution.TaskQueue,
   386  		Status:           internalExecution.Status,
   387  	}
   388  
   389  	if internalExecution.ParentWorkflowID != "" {
   390  		executionInfo.ParentExecution = &commonpb.WorkflowExecution{
   391  			WorkflowId: internalExecution.ParentWorkflowID,
   392  			RunId:      internalExecution.ParentRunID,
   393  		}
   394  	}
   395  
   396  	// for close records
   397  	if internalExecution.Status != enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING {
   398  		executionInfo.CloseTime = timestamppb.New(internalExecution.CloseTime)
   399  		executionInfo.HistoryLength = internalExecution.HistoryLength
   400  		executionInfo.HistorySizeBytes = internalExecution.HistorySizeBytes
   401  		executionInfo.StateTransitionCount = internalExecution.StateTransitionCount
   402  	}
   403  
   404  	// Workflows created before 1.11 have ExecutionTime set to Unix epoch zero time (1/1/1970) for non-cron/non-retry case.
   405  	// Use StartTime as ExecutionTime for this case (if there was a backoff it must be set).
   406  	// Remove this "if" block when ExecutionTime field has actual correct value (added 6/9/21).
   407  	// Affects only non-advanced visibility.
   408  	if !executionInfo.ExecutionTime.AsTime().After(time.Unix(0, 0)) {
   409  		executionInfo.ExecutionTime = executionInfo.StartTime
   410  	}
   411  
   412  	return executionInfo, nil
   413  }
   414  func (p *visibilityManagerImpl) deserializeMemo(data *commonpb.DataBlob) (*commonpb.Memo, error) {
   415  	if data == nil || len(data.Data) == 0 {
   416  		return &commonpb.Memo{}, nil
   417  	}
   418  
   419  	var ()
   420  	switch data.EncodingType {
   421  	case enumspb.ENCODING_TYPE_PROTO3:
   422  		memo := &commonpb.Memo{}
   423  		err := proto.Unmarshal(data.Data, memo)
   424  		if err != nil {
   425  			return nil, serviceerror.NewInternal(fmt.Sprintf("Unable to deserialize memo from data blob: %v", err))
   426  		}
   427  		return memo, nil
   428  	default:
   429  		return nil, serviceerror.NewInternal(fmt.Sprintf("Invalid memo encoding in database: %s", data.GetEncodingType().String()))
   430  	}
   431  }
   432  
   433  func (p *visibilityManagerImpl) serializeMemo(memo *commonpb.Memo) (*commonpb.DataBlob, error) {
   434  	if memo == nil {
   435  		memo = &commonpb.Memo{}
   436  	}
   437  
   438  	data, err := proto.Marshal(memo)
   439  	if err != nil {
   440  		return nil, serviceerror.NewInternal(fmt.Sprintf("Unable to serialize memo to data blob: %v", err))
   441  	}
   442  
   443  	return &commonpb.DataBlob{
   444  		Data:         data,
   445  		EncodingType: MemoEncoding,
   446  	}, nil
   447  }