go.temporal.io/server@v1.23.0/common/resource/fx.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 resource
    26  
    27  import (
    28  	"crypto/tls"
    29  	"fmt"
    30  	"net"
    31  	"os"
    32  	"time"
    33  
    34  	"go.uber.org/fx"
    35  	"google.golang.org/grpc"
    36  	"google.golang.org/grpc/health"
    37  
    38  	"go.temporal.io/api/workflowservice/v1"
    39  
    40  	"go.temporal.io/server/api/historyservice/v1"
    41  	"go.temporal.io/server/api/matchingservice/v1"
    42  	"go.temporal.io/server/client"
    43  	"go.temporal.io/server/client/frontend"
    44  	"go.temporal.io/server/client/history"
    45  	"go.temporal.io/server/client/matching"
    46  	"go.temporal.io/server/common"
    47  	"go.temporal.io/server/common/archiver"
    48  	"go.temporal.io/server/common/archiver/provider"
    49  	"go.temporal.io/server/common/clock"
    50  	"go.temporal.io/server/common/cluster"
    51  	"go.temporal.io/server/common/config"
    52  	"go.temporal.io/server/common/deadlock"
    53  	"go.temporal.io/server/common/dynamicconfig"
    54  	"go.temporal.io/server/common/log"
    55  	"go.temporal.io/server/common/log/tag"
    56  	"go.temporal.io/server/common/membership"
    57  	"go.temporal.io/server/common/membership/ringpop"
    58  	"go.temporal.io/server/common/metrics"
    59  	"go.temporal.io/server/common/namespace"
    60  	"go.temporal.io/server/common/persistence"
    61  	persistenceClient "go.temporal.io/server/common/persistence/client"
    62  	"go.temporal.io/server/common/persistence/serialization"
    63  	"go.temporal.io/server/common/primitives"
    64  	"go.temporal.io/server/common/quotas"
    65  	"go.temporal.io/server/common/rpc"
    66  	"go.temporal.io/server/common/rpc/encryption"
    67  	"go.temporal.io/server/common/sdk"
    68  	"go.temporal.io/server/common/searchattribute"
    69  	"go.temporal.io/server/common/telemetry"
    70  )
    71  
    72  type (
    73  	ThrottledLoggerRpsFn quotas.RateFn
    74  	NamespaceLogger      log.Logger
    75  	HostName             string
    76  	InstanceID           string
    77  	ServiceNames         map[primitives.ServiceName]struct{}
    78  
    79  	HistoryRawClient historyservice.HistoryServiceClient
    80  	HistoryClient    historyservice.HistoryServiceClient
    81  
    82  	MatchingRawClient matchingservice.MatchingServiceClient
    83  	MatchingClient    matchingservice.MatchingServiceClient
    84  
    85  	RuntimeMetricsReporterParams struct {
    86  		fx.In
    87  
    88  		MetricHandler metrics.Handler
    89  		Logger        log.SnTaggedLogger
    90  		InstanceID    InstanceID `optional:"true"`
    91  	}
    92  )
    93  
    94  // Module
    95  // Use fx.Hook and OnStart/OnStop to manage Daemon resource lifecycle
    96  // See LifetimeHooksModule for detail
    97  var Module = fx.Options(
    98  	persistenceClient.Module,
    99  	fx.Provide(HostNameProvider),
   100  	fx.Provide(TimeSourceProvider),
   101  	cluster.MetadataLifetimeHooksModule,
   102  	fx.Provide(SearchAttributeMapperProviderProvider),
   103  	fx.Provide(SearchAttributeProviderProvider),
   104  	fx.Provide(SearchAttributeManagerProvider),
   105  	fx.Provide(NamespaceRegistryProvider),
   106  	namespace.RegistryLifetimeHooksModule,
   107  	fx.Provide(fx.Annotate(
   108  		func(p namespace.Registry) common.Pingable { return p },
   109  		fx.ResultTags(`group:"deadlockDetectorRoots"`),
   110  	)),
   111  	fx.Provide(serialization.NewSerializer),
   112  	fx.Provide(HistoryBootstrapContainerProvider),
   113  	fx.Provide(VisibilityBootstrapContainerProvider),
   114  	fx.Provide(ClientFactoryProvider),
   115  	fx.Provide(ClientBeanProvider),
   116  	fx.Provide(FrontendClientProvider),
   117  	fx.Provide(GrpcListenerProvider),
   118  	fx.Provide(RuntimeMetricsReporterProvider),
   119  	metrics.RuntimeMetricsReporterLifetimeHooksModule,
   120  	fx.Provide(HistoryRawClientProvider),
   121  	fx.Provide(HistoryClientProvider),
   122  	fx.Provide(MatchingRawClientProvider),
   123  	fx.Provide(MatchingClientProvider),
   124  	membership.GRPCResolverModule,
   125  	fx.Invoke(RegisterBootstrapContainer),
   126  	fx.Provide(PersistenceConfigProvider),
   127  	fx.Provide(health.NewServer),
   128  	deadlock.Module,
   129  	config.Module,
   130  )
   131  
   132  var DefaultOptions = fx.Options(
   133  	ringpop.Module,
   134  	fx.Provide(RPCFactoryProvider),
   135  	fx.Provide(ArchivalMetadataProvider),
   136  	fx.Provide(ArchiverProviderProvider),
   137  	fx.Provide(ThrottledLoggerProvider),
   138  	fx.Provide(SdkClientFactoryProvider),
   139  	fx.Provide(DCRedirectionPolicyProvider),
   140  )
   141  
   142  func DefaultSnTaggedLoggerProvider(logger log.Logger, sn primitives.ServiceName) log.SnTaggedLogger {
   143  	return log.With(logger, tag.Service(sn))
   144  }
   145  
   146  func ThrottledLoggerProvider(
   147  	logger log.SnTaggedLogger,
   148  	fn ThrottledLoggerRpsFn,
   149  ) log.ThrottledLogger {
   150  	return log.NewThrottledLogger(
   151  		logger,
   152  		quotas.RateFn(fn),
   153  	)
   154  }
   155  
   156  func GrpcListenerProvider(factory common.RPCFactory) net.Listener {
   157  	return factory.GetGRPCListener()
   158  }
   159  
   160  func HostNameProvider() (HostName, error) {
   161  	hn, err := os.Hostname()
   162  	return HostName(hn), err
   163  }
   164  
   165  func TimeSourceProvider() clock.TimeSource {
   166  	return clock.NewRealTimeSource()
   167  }
   168  
   169  func SearchAttributeMapperProviderProvider(
   170  	saMapper searchattribute.Mapper,
   171  	namespaceRegistry namespace.Registry,
   172  	searchAttributeProvider searchattribute.Provider,
   173  	persistenceConfig *config.Persistence,
   174  ) searchattribute.MapperProvider {
   175  	return searchattribute.NewMapperProvider(
   176  		saMapper,
   177  		namespaceRegistry,
   178  		searchAttributeProvider,
   179  		persistenceConfig.IsSQLVisibilityStore(),
   180  	)
   181  }
   182  
   183  func SearchAttributeProviderProvider(
   184  	timeSource clock.TimeSource,
   185  	cmMgr persistence.ClusterMetadataManager,
   186  	dynamicCollection *dynamicconfig.Collection,
   187  ) searchattribute.Provider {
   188  	return searchattribute.NewManager(
   189  		timeSource,
   190  		cmMgr,
   191  		dynamicCollection.GetBoolProperty(dynamicconfig.ForceSearchAttributesCacheRefreshOnRead, false))
   192  }
   193  
   194  func SearchAttributeManagerProvider(
   195  	timeSource clock.TimeSource,
   196  	cmMgr persistence.ClusterMetadataManager,
   197  	dynamicCollection *dynamicconfig.Collection,
   198  ) searchattribute.Manager {
   199  	return searchattribute.NewManager(
   200  		timeSource,
   201  		cmMgr,
   202  		dynamicCollection.GetBoolProperty(dynamicconfig.ForceSearchAttributesCacheRefreshOnRead, false))
   203  }
   204  
   205  func NamespaceRegistryProvider(
   206  	logger log.SnTaggedLogger,
   207  	metricsHandler metrics.Handler,
   208  	clusterMetadata cluster.Metadata,
   209  	metadataManager persistence.MetadataManager,
   210  	dynamicCollection *dynamicconfig.Collection,
   211  ) namespace.Registry {
   212  	return namespace.NewRegistry(
   213  		metadataManager,
   214  		clusterMetadata.IsGlobalNamespaceEnabled(),
   215  		dynamicCollection.GetDurationProperty(dynamicconfig.NamespaceCacheRefreshInterval, 10*time.Second),
   216  		dynamicCollection.GetBoolProperty(dynamicconfig.ForceSearchAttributesCacheRefreshOnRead, false),
   217  		metricsHandler,
   218  		logger,
   219  	)
   220  }
   221  
   222  func ClientFactoryProvider(
   223  	factoryProvider client.FactoryProvider,
   224  	rpcFactory common.RPCFactory,
   225  	membershipMonitor membership.Monitor,
   226  	metricsHandler metrics.Handler,
   227  	dynamicCollection *dynamicconfig.Collection,
   228  	persistenceConfig *config.Persistence,
   229  	logger log.SnTaggedLogger,
   230  	throttledLogger log.ThrottledLogger,
   231  ) client.Factory {
   232  	return factoryProvider.NewFactory(
   233  		rpcFactory,
   234  		membershipMonitor,
   235  		metricsHandler,
   236  		dynamicCollection,
   237  		persistenceConfig.NumHistoryShards,
   238  		logger,
   239  		throttledLogger,
   240  	)
   241  }
   242  
   243  func ClientBeanProvider(
   244  	clientFactory client.Factory,
   245  	clusterMetadata cluster.Metadata,
   246  ) (client.Bean, error) {
   247  	return client.NewClientBean(
   248  		clientFactory,
   249  		clusterMetadata,
   250  	)
   251  }
   252  
   253  func FrontendClientProvider(clientBean client.Bean) workflowservice.WorkflowServiceClient {
   254  	frontendRawClient := clientBean.GetFrontendClient()
   255  	return frontend.NewRetryableClient(
   256  		frontendRawClient,
   257  		common.CreateFrontendClientRetryPolicy(),
   258  		common.IsServiceClientTransientError,
   259  	)
   260  }
   261  
   262  func RuntimeMetricsReporterProvider(
   263  	params RuntimeMetricsReporterParams,
   264  ) *metrics.RuntimeMetricsReporter {
   265  	return metrics.NewRuntimeMetricsReporter(
   266  		params.MetricHandler,
   267  		time.Minute,
   268  		params.Logger,
   269  		string(params.InstanceID),
   270  	)
   271  }
   272  
   273  func VisibilityBootstrapContainerProvider(
   274  	logger log.SnTaggedLogger,
   275  	metricsHandler metrics.Handler,
   276  	clusterMetadata cluster.Metadata,
   277  ) *archiver.VisibilityBootstrapContainer {
   278  	return &archiver.VisibilityBootstrapContainer{
   279  		Logger:          logger,
   280  		MetricsHandler:  metricsHandler,
   281  		ClusterMetadata: clusterMetadata,
   282  	}
   283  }
   284  
   285  func HistoryBootstrapContainerProvider(
   286  	logger log.SnTaggedLogger,
   287  	metricsHandler metrics.Handler,
   288  	clusterMetadata cluster.Metadata,
   289  	executionManager persistence.ExecutionManager,
   290  ) *archiver.HistoryBootstrapContainer {
   291  	return &archiver.HistoryBootstrapContainer{
   292  		ExecutionManager: executionManager,
   293  		Logger:           logger,
   294  		MetricsHandler:   metricsHandler,
   295  		ClusterMetadata:  clusterMetadata,
   296  	}
   297  }
   298  
   299  func RegisterBootstrapContainer(
   300  	archiverProvider provider.ArchiverProvider,
   301  	serviceName primitives.ServiceName,
   302  	visibilityArchiverBootstrapContainer *archiver.VisibilityBootstrapContainer,
   303  	historyArchiverBootstrapContainer *archiver.HistoryBootstrapContainer,
   304  ) error {
   305  	return archiverProvider.RegisterBootstrapContainer(
   306  		string(serviceName),
   307  		historyArchiverBootstrapContainer,
   308  		visibilityArchiverBootstrapContainer,
   309  	)
   310  }
   311  
   312  func HistoryRawClientProvider(clientBean client.Bean) HistoryRawClient {
   313  	return clientBean.GetHistoryClient()
   314  }
   315  
   316  func HistoryClientProvider(historyRawClient HistoryRawClient) HistoryClient {
   317  	return history.NewRetryableClient(
   318  		historyRawClient,
   319  		common.CreateHistoryClientRetryPolicy(),
   320  		common.IsServiceClientTransientError,
   321  	)
   322  }
   323  
   324  func MatchingRawClientProvider(
   325  	clientBean client.Bean,
   326  	namespaceRegistry namespace.Registry,
   327  ) (MatchingRawClient, error) {
   328  	return clientBean.GetMatchingClient(namespaceRegistry.GetNamespaceName)
   329  }
   330  
   331  func MatchingClientProvider(matchingRawClient MatchingRawClient) MatchingClient {
   332  	return matching.NewRetryableClient(
   333  		matchingRawClient,
   334  		common.CreateMatchingClientRetryPolicy(),
   335  		common.IsServiceClientTransientError,
   336  	)
   337  }
   338  
   339  func PersistenceConfigProvider(persistenceConfig config.Persistence, dc *dynamicconfig.Collection) *config.Persistence {
   340  	persistenceConfig.TransactionSizeLimit = dc.GetIntProperty(dynamicconfig.TransactionSizeLimit, common.DefaultTransactionSizeLimit)
   341  	return &persistenceConfig
   342  }
   343  
   344  func ArchivalMetadataProvider(dc *dynamicconfig.Collection, cfg *config.Config) archiver.ArchivalMetadata {
   345  	return archiver.NewArchivalMetadata(
   346  		dc,
   347  		cfg.Archival.History.State,
   348  		cfg.Archival.History.EnableRead,
   349  		cfg.Archival.Visibility.State,
   350  		cfg.Archival.Visibility.EnableRead,
   351  		&cfg.NamespaceDefaults.Archival,
   352  	)
   353  }
   354  
   355  func ArchiverProviderProvider(cfg *config.Config) provider.ArchiverProvider {
   356  	return provider.NewArchiverProvider(cfg.Archival.History.Provider, cfg.Archival.Visibility.Provider)
   357  }
   358  
   359  func SdkClientFactoryProvider(
   360  	cfg *config.Config,
   361  	tlsConfigProvider encryption.TLSConfigProvider,
   362  	metricsHandler metrics.Handler,
   363  	logger log.SnTaggedLogger,
   364  	resolver membership.GRPCResolver,
   365  	dc *dynamicconfig.Collection,
   366  ) (sdk.ClientFactory, error) {
   367  	frontendURL, frontendTLSConfig, err := getFrontendConnectionDetails(cfg, tlsConfigProvider, resolver)
   368  	if err != nil {
   369  		return nil, err
   370  	}
   371  	return sdk.NewClientFactory(
   372  		frontendURL,
   373  		frontendTLSConfig,
   374  		metricsHandler,
   375  		logger,
   376  		dc.GetIntProperty(dynamicconfig.WorkerStickyCacheSize, 0),
   377  	), nil
   378  }
   379  
   380  func DCRedirectionPolicyProvider(cfg *config.Config) config.DCRedirectionPolicy {
   381  	return cfg.DCRedirectionPolicy
   382  }
   383  
   384  func RPCFactoryProvider(
   385  	cfg *config.Config,
   386  	svcName primitives.ServiceName,
   387  	logger log.Logger,
   388  	tlsConfigProvider encryption.TLSConfigProvider,
   389  	resolver membership.GRPCResolver,
   390  	traceInterceptor telemetry.ClientTraceInterceptor,
   391  ) (common.RPCFactory, error) {
   392  	svcCfg := cfg.Services[string(svcName)]
   393  	frontendURL, frontendTLSConfig, err := getFrontendConnectionDetails(cfg, tlsConfigProvider, resolver)
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  	return rpc.NewFactory(
   398  		&svcCfg.RPC,
   399  		svcName,
   400  		logger,
   401  		tlsConfigProvider,
   402  		frontendURL,
   403  		frontendTLSConfig,
   404  		[]grpc.UnaryClientInterceptor{
   405  			grpc.UnaryClientInterceptor(traceInterceptor),
   406  		},
   407  	), nil
   408  }
   409  
   410  func getFrontendConnectionDetails(
   411  	cfg *config.Config,
   412  	tlsConfigProvider encryption.TLSConfigProvider,
   413  	resolver membership.GRPCResolver,
   414  ) (string, *tls.Config, error) {
   415  	// To simplify the static config, we switch default values based on whether the config
   416  	// defines an "internal-frontend" service. The default for TLS config can be overridden
   417  	// with publicClient.forceTLSConfig, and the default for hostPort can be overridden by
   418  	// explicitly setting hostPort to "membership://internal-frontend" or
   419  	// "membership://frontend".
   420  	_, hasIFE := cfg.Services[string(primitives.InternalFrontendService)]
   421  
   422  	forceTLS := cfg.PublicClient.ForceTLSConfig
   423  	if forceTLS == config.ForceTLSConfigAuto {
   424  		if hasIFE {
   425  			forceTLS = config.ForceTLSConfigInternode
   426  		} else {
   427  			forceTLS = config.ForceTLSConfigFrontend
   428  		}
   429  	}
   430  
   431  	var frontendTLSConfig *tls.Config
   432  	var err error
   433  	switch forceTLS {
   434  	case config.ForceTLSConfigInternode:
   435  		frontendTLSConfig, err = tlsConfigProvider.GetInternodeClientConfig()
   436  	case config.ForceTLSConfigFrontend:
   437  		frontendTLSConfig, err = tlsConfigProvider.GetFrontendClientConfig()
   438  	default:
   439  		err = fmt.Errorf("invalid forceTLSConfig")
   440  	}
   441  	if err != nil {
   442  		return "", nil, fmt.Errorf("unable to load TLS configuration: %w", err)
   443  	}
   444  
   445  	frontendURL := cfg.PublicClient.HostPort
   446  	if frontendURL == "" {
   447  		if hasIFE {
   448  			frontendURL = resolver.MakeURL(primitives.InternalFrontendService)
   449  		} else {
   450  			frontendURL = resolver.MakeURL(primitives.FrontendService)
   451  		}
   452  	}
   453  
   454  	return frontendURL, frontendTLSConfig, nil
   455  }