go.temporal.io/server@v1.23.0/common/persistence/visibility/factory.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  	"go.temporal.io/server/common/config"
    29  	"go.temporal.io/server/common/dynamicconfig"
    30  	"go.temporal.io/server/common/log"
    31  	"go.temporal.io/server/common/log/tag"
    32  	"go.temporal.io/server/common/metrics"
    33  	"go.temporal.io/server/common/persistence/sql/sqlplugin/mysql"
    34  	"go.temporal.io/server/common/persistence/sql/sqlplugin/postgresql"
    35  	"go.temporal.io/server/common/persistence/sql/sqlplugin/sqlite"
    36  	"go.temporal.io/server/common/persistence/visibility/manager"
    37  	"go.temporal.io/server/common/persistence/visibility/store"
    38  	"go.temporal.io/server/common/persistence/visibility/store/elasticsearch"
    39  	esclient "go.temporal.io/server/common/persistence/visibility/store/elasticsearch/client"
    40  	"go.temporal.io/server/common/persistence/visibility/store/sql"
    41  	"go.temporal.io/server/common/persistence/visibility/store/standard"
    42  	"go.temporal.io/server/common/persistence/visibility/store/standard/cassandra"
    43  	standardSql "go.temporal.io/server/common/persistence/visibility/store/standard/sql"
    44  	"go.temporal.io/server/common/resolver"
    45  	"go.temporal.io/server/common/searchattribute"
    46  )
    47  
    48  type VisibilityStoreFactory interface {
    49  	NewVisibilityStore(
    50  		cfg config.CustomDatastoreConfig,
    51  		r resolver.ServiceResolver,
    52  		logger log.Logger,
    53  		metricsHandler metrics.Handler,
    54  	) (store.VisibilityStore, error)
    55  }
    56  
    57  func NewManager(
    58  	persistenceCfg config.Persistence,
    59  	persistenceResolver resolver.ServiceResolver,
    60  	customVisibilityStoreFactory VisibilityStoreFactory,
    61  
    62  	esClient esclient.Client,
    63  	esProcessorConfig *elasticsearch.ProcessorConfig,
    64  	searchAttributesProvider searchattribute.Provider,
    65  	searchAttributesMapperProvider searchattribute.MapperProvider,
    66  
    67  	maxReadQPS dynamicconfig.IntPropertyFn,
    68  	maxWriteQPS dynamicconfig.IntPropertyFn,
    69  	operatorRPSRatio dynamicconfig.FloatPropertyFn,
    70  	enableReadFromSecondaryVisibility dynamicconfig.BoolPropertyFnWithNamespaceFilter,
    71  	secondaryVisibilityWritingMode dynamicconfig.StringPropertyFn,
    72  	visibilityDisableOrderByClause dynamicconfig.BoolPropertyFnWithNamespaceFilter,
    73  	visibilityEnableManualPagination dynamicconfig.BoolPropertyFnWithNamespaceFilter,
    74  
    75  	metricsHandler metrics.Handler,
    76  	logger log.Logger,
    77  ) (manager.VisibilityManager, error) {
    78  	visibilityManager, err := newVisibilityManagerFromDataStoreConfig(
    79  		persistenceCfg.GetVisibilityStoreConfig(),
    80  		persistenceResolver,
    81  		customVisibilityStoreFactory,
    82  		esClient,
    83  		esProcessorConfig,
    84  		searchAttributesProvider,
    85  		searchAttributesMapperProvider,
    86  		maxReadQPS,
    87  		maxWriteQPS,
    88  		operatorRPSRatio,
    89  		visibilityDisableOrderByClause,
    90  		visibilityEnableManualPagination,
    91  		metricsHandler,
    92  		logger,
    93  	)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  	if visibilityManager == nil {
    98  		logger.Fatal("invalid config: visibility store must be configured")
    99  		return nil, nil
   100  	}
   101  
   102  	secondaryVisibilityManager, err := newVisibilityManagerFromDataStoreConfig(
   103  		persistenceCfg.GetSecondaryVisibilityStoreConfig(),
   104  		persistenceResolver,
   105  		customVisibilityStoreFactory,
   106  		esClient,
   107  		esProcessorConfig,
   108  		searchAttributesProvider,
   109  		searchAttributesMapperProvider,
   110  		maxReadQPS,
   111  		maxWriteQPS,
   112  		operatorRPSRatio,
   113  		visibilityDisableOrderByClause,
   114  		visibilityEnableManualPagination,
   115  		metricsHandler,
   116  		logger,
   117  	)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	if secondaryVisibilityManager != nil {
   123  		isPrimaryAdvancedSQL := false
   124  		isSecondaryAdvancedSQL := false
   125  		switch visibilityManager.GetStoreNames()[0] {
   126  		case mysql.PluginNameV8, postgresql.PluginNameV12, postgresql.PluginNameV12PGX, sqlite.PluginName:
   127  			isPrimaryAdvancedSQL = true
   128  		}
   129  		switch secondaryVisibilityManager.GetStoreNames()[0] {
   130  		case mysql.PluginNameV8, postgresql.PluginNameV12, postgresql.PluginNameV12PGX, sqlite.PluginName:
   131  			isSecondaryAdvancedSQL = true
   132  		}
   133  		if isPrimaryAdvancedSQL && !isSecondaryAdvancedSQL {
   134  			logger.Fatal("invalid config: dual visibility combination not supported")
   135  			return nil, nil
   136  		}
   137  
   138  		managerSelector := newDefaultManagerSelector(
   139  			visibilityManager,
   140  			secondaryVisibilityManager,
   141  			enableReadFromSecondaryVisibility,
   142  			secondaryVisibilityWritingMode,
   143  		)
   144  		return NewVisibilityManagerDual(
   145  			visibilityManager,
   146  			secondaryVisibilityManager,
   147  			managerSelector,
   148  		), nil
   149  	}
   150  
   151  	return visibilityManager, nil
   152  }
   153  
   154  func newVisibilityManager(
   155  	visStore store.VisibilityStore,
   156  	maxReadQPS dynamicconfig.IntPropertyFn,
   157  	maxWriteQPS dynamicconfig.IntPropertyFn,
   158  	operatorRPSRatio dynamicconfig.FloatPropertyFn,
   159  	metricsHandler metrics.Handler,
   160  	visibilityPluginNameTag metrics.Tag,
   161  	logger log.Logger,
   162  ) manager.VisibilityManager {
   163  	if visStore == nil {
   164  		return nil
   165  	}
   166  	logger.Info(
   167  		"creating new visibility manager",
   168  		tag.NewStringTag(visibilityPluginNameTag.Key(), visibilityPluginNameTag.Value()),
   169  		tag.NewStringTag("visibility_index_name", visStore.GetIndexName()),
   170  	)
   171  	var visManager manager.VisibilityManager = newVisibilityManagerImpl(visStore, logger)
   172  
   173  	// wrap with rate limiter
   174  	visManager = NewVisibilityManagerRateLimited(
   175  		visManager,
   176  		maxReadQPS,
   177  		maxWriteQPS,
   178  		operatorRPSRatio,
   179  	)
   180  	// wrap with metrics client
   181  	visManager = NewVisibilityManagerMetrics(
   182  		visManager,
   183  		metricsHandler,
   184  		logger,
   185  		visibilityPluginNameTag,
   186  	)
   187  	return visManager
   188  }
   189  
   190  //nolint:revive // too many arguments
   191  func newVisibilityManagerFromDataStoreConfig(
   192  	dsConfig config.DataStore,
   193  	persistenceResolver resolver.ServiceResolver,
   194  	customVisibilityStoreFactory VisibilityStoreFactory,
   195  
   196  	esClient esclient.Client,
   197  	esProcessorConfig *elasticsearch.ProcessorConfig,
   198  	searchAttributesProvider searchattribute.Provider,
   199  	searchAttributesMapperProvider searchattribute.MapperProvider,
   200  
   201  	maxReadQPS dynamicconfig.IntPropertyFn,
   202  	maxWriteQPS dynamicconfig.IntPropertyFn,
   203  	operatorRPSRatio dynamicconfig.FloatPropertyFn,
   204  	visibilityDisableOrderByClause dynamicconfig.BoolPropertyFnWithNamespaceFilter,
   205  	visibilityEnableManualPagination dynamicconfig.BoolPropertyFnWithNamespaceFilter,
   206  
   207  	metricsHandler metrics.Handler,
   208  	logger log.Logger,
   209  ) (manager.VisibilityManager, error) {
   210  	visStore, err := newVisibilityStoreFromDataStoreConfig(
   211  		dsConfig,
   212  		persistenceResolver,
   213  		customVisibilityStoreFactory,
   214  		esClient,
   215  		esProcessorConfig,
   216  		searchAttributesProvider,
   217  		searchAttributesMapperProvider,
   218  		visibilityDisableOrderByClause,
   219  		visibilityEnableManualPagination,
   220  		metricsHandler,
   221  		logger,
   222  	)
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  	if visStore == nil {
   227  		return nil, nil
   228  	}
   229  	return newVisibilityManager(
   230  		visStore,
   231  		maxReadQPS,
   232  		maxWriteQPS,
   233  		operatorRPSRatio,
   234  		metricsHandler,
   235  		metrics.VisibilityPluginNameTag(visStore.GetName()),
   236  		logger,
   237  	), nil
   238  }
   239  
   240  func newVisibilityStoreFromDataStoreConfig(
   241  	dsConfig config.DataStore,
   242  	persistenceResolver resolver.ServiceResolver,
   243  	customVisibilityStoreFactory VisibilityStoreFactory,
   244  
   245  	esClient esclient.Client,
   246  	esProcessorConfig *elasticsearch.ProcessorConfig,
   247  	searchAttributesProvider searchattribute.Provider,
   248  	searchAttributesMapperProvider searchattribute.MapperProvider,
   249  	visibilityDisableOrderByClause dynamicconfig.BoolPropertyFnWithNamespaceFilter,
   250  	visibilityEnableManualPagination dynamicconfig.BoolPropertyFnWithNamespaceFilter,
   251  
   252  	metricsHandler metrics.Handler,
   253  	logger log.Logger,
   254  ) (store.VisibilityStore, error) {
   255  	var (
   256  		visStore store.VisibilityStore
   257  		err      error
   258  	)
   259  	if dsConfig.SQL != nil {
   260  		switch dsConfig.SQL.PluginName {
   261  		case mysql.PluginNameV8, postgresql.PluginNameV12, postgresql.PluginNameV12PGX, sqlite.PluginName:
   262  			visStore, err = sql.NewSQLVisibilityStore(
   263  				*dsConfig.SQL,
   264  				persistenceResolver,
   265  				searchAttributesProvider,
   266  				searchAttributesMapperProvider,
   267  				logger,
   268  			)
   269  		default:
   270  			visStore, err = newStandardVisibilityStore(
   271  				dsConfig,
   272  				persistenceResolver,
   273  				searchAttributesProvider,
   274  				searchAttributesMapperProvider,
   275  				logger,
   276  				metricsHandler,
   277  			)
   278  		}
   279  	} else if dsConfig.Cassandra != nil {
   280  		visStore, err = newStandardVisibilityStore(
   281  			dsConfig,
   282  			persistenceResolver,
   283  			searchAttributesProvider,
   284  			searchAttributesMapperProvider,
   285  			logger,
   286  			metricsHandler,
   287  		)
   288  	} else if dsConfig.Elasticsearch != nil {
   289  		visStore = newElasticsearchVisibilityStore(
   290  			dsConfig.Elasticsearch.GetVisibilityIndex(),
   291  			esClient,
   292  			esProcessorConfig,
   293  			searchAttributesProvider,
   294  			searchAttributesMapperProvider,
   295  			visibilityDisableOrderByClause,
   296  			visibilityEnableManualPagination,
   297  			metricsHandler,
   298  			logger,
   299  		)
   300  	} else if dsConfig.CustomDataStoreConfig != nil {
   301  		visStore, err = customVisibilityStoreFactory.NewVisibilityStore(
   302  			*dsConfig.CustomDataStoreConfig,
   303  			persistenceResolver,
   304  			logger,
   305  			metricsHandler,
   306  		)
   307  	}
   308  	return visStore, err
   309  }
   310  
   311  func newStandardVisibilityStore(
   312  	dsConfig config.DataStore,
   313  	persistenceResolver resolver.ServiceResolver,
   314  	searchAttributesProvider searchattribute.Provider,
   315  	searchAttributesMapperProvider searchattribute.MapperProvider,
   316  	logger log.Logger,
   317  	metricsHandler metrics.Handler,
   318  ) (store.VisibilityStore, error) {
   319  	var (
   320  		visStore store.VisibilityStore
   321  		err      error
   322  	)
   323  	if dsConfig.Cassandra != nil {
   324  		visStore, err = cassandra.NewVisibilityStore(
   325  			*dsConfig.Cassandra,
   326  			persistenceResolver,
   327  			logger,
   328  			metricsHandler,
   329  		)
   330  	} else if dsConfig.SQL != nil {
   331  		visStore, err = standardSql.NewSQLVisibilityStore(
   332  			*dsConfig.SQL,
   333  			persistenceResolver,
   334  			logger,
   335  		)
   336  	}
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  	if visStore == nil {
   341  		logger.Fatal("invalid config: one of cassandra or sql params must be specified for visibility store")
   342  		return nil, nil
   343  	}
   344  	return standard.NewVisibilityStore(
   345  		visStore,
   346  		searchAttributesProvider,
   347  		searchAttributesMapperProvider,
   348  	), nil
   349  }
   350  
   351  func newElasticsearchVisibilityStore(
   352  	defaultIndexName string,
   353  	esClient esclient.Client,
   354  	esProcessorConfig *elasticsearch.ProcessorConfig,
   355  	searchAttributesProvider searchattribute.Provider,
   356  	searchAttributesMapperProvider searchattribute.MapperProvider,
   357  	visibilityDisableOrderByClause dynamicconfig.BoolPropertyFnWithNamespaceFilter,
   358  	visibilityEnableManualPagination dynamicconfig.BoolPropertyFnWithNamespaceFilter,
   359  	metricsHandler metrics.Handler,
   360  	logger log.Logger,
   361  ) store.VisibilityStore {
   362  	if esClient == nil {
   363  		return nil
   364  	}
   365  
   366  	var (
   367  		esProcessor           elasticsearch.Processor
   368  		esProcessorAckTimeout dynamicconfig.DurationPropertyFn
   369  	)
   370  	if esProcessorConfig != nil {
   371  		esProcessor = elasticsearch.NewProcessor(esProcessorConfig, esClient, logger, metricsHandler)
   372  		esProcessor.Start()
   373  		esProcessorAckTimeout = esProcessorConfig.ESProcessorAckTimeout
   374  	}
   375  	s := elasticsearch.NewVisibilityStore(
   376  		esClient,
   377  		defaultIndexName,
   378  		searchAttributesProvider,
   379  		searchAttributesMapperProvider,
   380  		esProcessor,
   381  		esProcessorAckTimeout,
   382  		visibilityDisableOrderByClause,
   383  		visibilityEnableManualPagination,
   384  		metricsHandler)
   385  	return s
   386  }