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 }