snapshot of https://github.com/centrifugal/centrifugo.git (master, 2026-09-16; blobs > 131072B omitted)
This commit is contained in:
326
internal/app/engine.go
Normal file
326
internal/app/engine.go
Normal file
@@ -0,0 +1,326 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/centrifugal/centrifugo/v6/internal/config"
|
||||
"github.com/centrifugal/centrifugo/v6/internal/confighelpers"
|
||||
"github.com/centrifugal/centrifugo/v6/internal/configtypes"
|
||||
"github.com/centrifugal/centrifugo/v6/internal/controllers"
|
||||
"github.com/centrifugal/centrifugo/v6/internal/natsbroker"
|
||||
"github.com/centrifugal/centrifugo/v6/internal/pgmapbroker"
|
||||
"github.com/centrifugal/centrifugo/v6/internal/pgstreambroker"
|
||||
"github.com/centrifugal/centrifugo/v6/internal/redisnatsbroker"
|
||||
|
||||
"github.com/centrifugal/centrifuge"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func configureEngines(node *centrifuge.Node, cfgContainer *config.Container) error {
|
||||
cfg := cfgContainer.Config()
|
||||
|
||||
var broker centrifuge.Broker
|
||||
var presenceManager centrifuge.PresenceManager
|
||||
|
||||
if !cfg.Broker.Enabled || !cfg.PresenceManager.Enabled {
|
||||
var err error
|
||||
var engineMode string
|
||||
switch cfg.Engine.Type {
|
||||
case "memory":
|
||||
broker, presenceManager, err = createMemoryEngine(node)
|
||||
case "redis":
|
||||
broker, presenceManager, engineMode, err = createRedisEngine(node, cfgContainer)
|
||||
default:
|
||||
return fmt.Errorf("unknown engine type: %s", cfg.Engine.Type)
|
||||
}
|
||||
event := log.Info().Str("engine_type", cfg.Engine.Type)
|
||||
if engineMode != "" {
|
||||
event.Str("engine_mode", engineMode)
|
||||
}
|
||||
event.Msg("initializing engine")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating engine: %v", err)
|
||||
}
|
||||
} else {
|
||||
log.Info().Msgf("both broker and presence manager enabled, skip engine initialization")
|
||||
}
|
||||
|
||||
if cfg.Broker.Enabled {
|
||||
var err error
|
||||
var brokerMode string
|
||||
switch cfg.Broker.Type {
|
||||
case "memory":
|
||||
broker, err = createMemoryBroker(node)
|
||||
case "redis":
|
||||
broker, brokerMode, err = createRedisBroker(node, cfgContainer)
|
||||
case "nats":
|
||||
broker, err = NatsBroker(node, cfg)
|
||||
brokerMode = "nats"
|
||||
case "postgres":
|
||||
broker, err = createPostgresStreamBroker(node, cfg.Broker.Postgres)
|
||||
brokerMode = "postgres"
|
||||
case "redisnats":
|
||||
if !cfg.EnableUnreleasedFeatures {
|
||||
return fmt.Errorf("redisnats broker requires enable_unreleased_features on")
|
||||
}
|
||||
log.Warn().Msg("redisnats broker is not released, it may be changed or removed at any point")
|
||||
redisBroker, redisBrokerMode, err := createRedisBroker(node, cfgContainer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating redis broker: %v", err)
|
||||
}
|
||||
brokerMode = redisBrokerMode + "+nats"
|
||||
natsBroker, err := NatsBroker(node, cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating nats broker: %v", err)
|
||||
}
|
||||
broker, err = redisnatsbroker.New(natsBroker, redisBroker)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating redisnats broker: %v", err)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown broker type: %s", cfg.Broker.Type)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating broker: %v", err)
|
||||
}
|
||||
event := log.Info().Str("broker_type", cfg.Broker.Type)
|
||||
if brokerMode != "" {
|
||||
event.Str("broker_mode", brokerMode)
|
||||
}
|
||||
event.Msg("broker is enabled, using it instead of broker from engine")
|
||||
} else {
|
||||
log.Info().Msgf("explicit broker not provided, using the one from engine")
|
||||
}
|
||||
|
||||
if cfg.PresenceManager.Enabled {
|
||||
var err error
|
||||
var presenceManagerMode string
|
||||
switch cfg.PresenceManager.Type {
|
||||
case "memory":
|
||||
presenceManager, err = createMemoryPresenceManager(node)
|
||||
case "redis":
|
||||
presenceManager, presenceManagerMode, err = createRedisPresenceManager(node, cfgContainer)
|
||||
default:
|
||||
return fmt.Errorf("unknown presence manager type: %s", cfg.PresenceManager.Type)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating presence manager: %v", err)
|
||||
}
|
||||
event := log.Info().Str("presence_manager_type", cfg.PresenceManager.Type)
|
||||
if presenceManagerMode != "" {
|
||||
event.Str("presence_manager_mode", presenceManagerMode)
|
||||
}
|
||||
event.Msg("presence manager is enabled, using it instead of presence manager from engine")
|
||||
} else {
|
||||
log.Info().Msgf("explicit presence manager not provided, using the one from engine")
|
||||
}
|
||||
|
||||
if cfg.Controller.Enabled {
|
||||
controller, err := controllers.New(node, cfg.Controller)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating controller: %v", err)
|
||||
}
|
||||
if controller != nil {
|
||||
node.SetController(controller)
|
||||
}
|
||||
}
|
||||
|
||||
node.SetBroker(broker)
|
||||
node.SetPresenceManager(presenceManager)
|
||||
return nil
|
||||
}
|
||||
|
||||
func createMemoryBroker(n *centrifuge.Node) (centrifuge.Broker, error) {
|
||||
brokerConf, err := memoryBrokerConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
broker, err := centrifuge.NewMemoryBroker(n, *brokerConf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return broker, nil
|
||||
}
|
||||
|
||||
func createPostgresStreamBroker(node *centrifuge.Node, pgCfg configtypes.PostgresStreamBroker) (centrifuge.Broker, error) {
|
||||
pgBrokerCfg := pgstreambroker.PostgresStreamBrokerConfig{
|
||||
DSN: pgCfg.DSN,
|
||||
TLS: pgCfg.TLS,
|
||||
PoolSize: pgCfg.PoolSize,
|
||||
NumShards: pgCfg.NumShards,
|
||||
CleanupInterval: pgCfg.CleanupInterval.ToDuration(),
|
||||
IdempotentResultTTL: pgCfg.IdempotentResultTTL.ToDuration(),
|
||||
BinaryData: pgCfg.BinaryData,
|
||||
StreamRetention: pgCfg.StreamRetention.ToDuration(),
|
||||
UseNotify: pgCfg.UseNotify,
|
||||
NotifyDSN: pgCfg.NotifyDSN,
|
||||
TablePrefix: pgCfg.TablePrefix,
|
||||
PartitionLookaheadDays: pgCfg.PartitionLookaheadDays,
|
||||
PartitionRetentionDays: pgCfg.PartitionRetentionDays,
|
||||
Outbox: pgstreambroker.OutboxConfig{
|
||||
PollInterval: pgCfg.Outbox.PollInterval.ToDuration(),
|
||||
BatchSize: pgCfg.Outbox.BatchSize,
|
||||
},
|
||||
}
|
||||
broker, err := pgstreambroker.NewPostgresStreamBroker(node, pgBrokerCfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating Postgres stream broker: %w", err)
|
||||
}
|
||||
if !pgCfg.SkipSchemaInit {
|
||||
if schemaErr := broker.EnsureSchema(context.Background()); schemaErr != nil {
|
||||
return nil, fmt.Errorf("error initializing Postgres stream broker schema: %w", schemaErr)
|
||||
}
|
||||
}
|
||||
return broker, nil
|
||||
}
|
||||
|
||||
func createMemoryPresenceManager(n *centrifuge.Node) (centrifuge.PresenceManager, error) {
|
||||
presenceManagerConf, err := memoryPresenceManagerConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return centrifuge.NewMemoryPresenceManager(n, *presenceManagerConf)
|
||||
}
|
||||
|
||||
func createMemoryEngine(n *centrifuge.Node) (centrifuge.Broker, centrifuge.PresenceManager, error) {
|
||||
broker, err := createMemoryBroker(n)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
presenceManager, err := createMemoryPresenceManager(n)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return broker, presenceManager, nil
|
||||
}
|
||||
|
||||
func memoryBrokerConfig() (*centrifuge.MemoryBrokerConfig, error) {
|
||||
return ¢rifuge.MemoryBrokerConfig{}, nil
|
||||
}
|
||||
|
||||
func memoryPresenceManagerConfig() (*centrifuge.MemoryPresenceManagerConfig, error) {
|
||||
return ¢rifuge.MemoryPresenceManagerConfig{}, nil
|
||||
}
|
||||
|
||||
func NatsBroker(node *centrifuge.Node, cfg config.Config) (*natsbroker.NatsBroker, error) {
|
||||
return natsbroker.New(node, cfg.Broker.Nats)
|
||||
}
|
||||
|
||||
func createRedisEngine(n *centrifuge.Node, cfgContainer *config.Container) (*centrifuge.RedisBroker, centrifuge.PresenceManager, string, error) {
|
||||
cfg := cfgContainer.Config()
|
||||
redisShards, mode, err := confighelpers.CentrifugeRedisShards(n, cfg.Engine.Redis.Redis)
|
||||
if err != nil {
|
||||
return nil, nil, mode, fmt.Errorf("error creating Redis shards: %w", err)
|
||||
}
|
||||
|
||||
var broker *centrifuge.RedisBroker
|
||||
if !cfg.Broker.Enabled {
|
||||
broker, err = confighelpers.CentrifugeRedisBroker(
|
||||
n, cfg.Engine.Redis.Prefix, redisShards, cfg.Engine.Redis.RedisBrokerCommon, false)
|
||||
if err != nil {
|
||||
return nil, nil, mode, fmt.Errorf("error creating Redis broker: %w", err)
|
||||
}
|
||||
}
|
||||
var presenceManager centrifuge.PresenceManager
|
||||
if !cfg.PresenceManager.Enabled {
|
||||
presenceManager, err = confighelpers.CentrifugeRedisPresenceManager(
|
||||
n, cfg.Engine.Redis.Prefix, redisShards, cfg.Engine.Redis.RedisPresenceManagerCommon)
|
||||
if err != nil {
|
||||
return nil, nil, mode, fmt.Errorf("error creating Redis presence manager: %w", err)
|
||||
}
|
||||
}
|
||||
return broker, presenceManager, mode, nil
|
||||
}
|
||||
|
||||
func createRedisBroker(n *centrifuge.Node, cfgContainer *config.Container) (*centrifuge.RedisBroker, string, error) {
|
||||
cfg := cfgContainer.Config()
|
||||
redisShards, mode, err := confighelpers.CentrifugeRedisShards(n, cfg.Broker.Redis.Redis)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("error creating Redis shards: %w", err)
|
||||
}
|
||||
broker, err := confighelpers.CentrifugeRedisBroker(
|
||||
n, cfg.Broker.Redis.Prefix, redisShards, cfg.Broker.Redis.RedisBrokerCommon, cfg.Broker.Type == "redisnats")
|
||||
if err != nil {
|
||||
return nil, mode, fmt.Errorf("error creating Redis broker: %w", err)
|
||||
}
|
||||
return broker, mode, nil
|
||||
}
|
||||
|
||||
func createRedisPresenceManager(n *centrifuge.Node, cfgContainer *config.Container) (centrifuge.PresenceManager, string, error) {
|
||||
cfg := cfgContainer.Config()
|
||||
redisShards, mode, err := confighelpers.CentrifugeRedisShards(n, cfg.PresenceManager.Redis.Redis)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("error creating Redis shards: %w", err)
|
||||
}
|
||||
presenceManager, err := confighelpers.CentrifugeRedisPresenceManager(
|
||||
n, cfg.PresenceManager.Redis.Prefix, redisShards, cfg.PresenceManager.Redis.RedisPresenceManagerCommon)
|
||||
if err != nil {
|
||||
return nil, mode, fmt.Errorf("error creating Redis presence manager: %w", err)
|
||||
}
|
||||
return presenceManager, mode, nil
|
||||
}
|
||||
|
||||
func configureMapBroker(node *centrifuge.Node, cfgContainer *config.Container) error {
|
||||
cfg := cfgContainer.Config()
|
||||
var mapBroker centrifuge.MapBroker
|
||||
var mapBrokerMode string
|
||||
var err error
|
||||
switch cfg.MapBroker.Type {
|
||||
case "memory":
|
||||
mapBroker, err = centrifuge.NewMemoryMapBroker(node, centrifuge.MemoryMapBrokerConfig{})
|
||||
case "redis":
|
||||
var redisShards []*centrifuge.RedisShard
|
||||
redisShards, mapBrokerMode, err = confighelpers.CentrifugeRedisShards(node, cfg.MapBroker.Redis.Redis)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating Redis shards for map broker: %w", err)
|
||||
}
|
||||
mapBroker, err = confighelpers.CentrifugeRedisMapBroker(
|
||||
node, cfg.MapBroker.Redis.Prefix, redisShards, cfg.MapBroker.Redis.RedisMapBrokerCommon)
|
||||
case "postgres":
|
||||
pgCfg := cfg.MapBroker.Postgres
|
||||
pgBrokerCfg := pgmapbroker.PostgresMapBrokerConfig{
|
||||
DSN: pgCfg.DSN,
|
||||
TLS: pgCfg.TLS,
|
||||
PoolSize: pgCfg.PoolSize,
|
||||
NumShards: pgCfg.NumShards,
|
||||
TTLCheckInterval: pgCfg.TTLCheckInterval.ToDuration(),
|
||||
CleanupInterval: pgCfg.CleanupInterval.ToDuration(),
|
||||
IdempotentResultTTL: pgCfg.IdempotentResultTTL.ToDuration(),
|
||||
BinaryData: pgCfg.BinaryData,
|
||||
StreamRetention: pgCfg.StreamRetention.ToDuration(),
|
||||
UseNotify: pgCfg.UseNotify,
|
||||
NotifyDSN: pgCfg.NotifyDSN,
|
||||
TablePrefix: pgCfg.TablePrefix,
|
||||
PartitionLookaheadDays: pgCfg.PartitionLookaheadDays,
|
||||
PartitionRetentionDays: pgCfg.PartitionRetentionDays,
|
||||
Outbox: pgmapbroker.OutboxConfig{
|
||||
PollInterval: pgCfg.Outbox.PollInterval.ToDuration(),
|
||||
BatchSize: pgCfg.Outbox.BatchSize,
|
||||
},
|
||||
}
|
||||
mapBroker, err = pgmapbroker.NewPostgresMapBroker(node, pgBrokerCfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating Postgres map broker: %w", err)
|
||||
}
|
||||
if !pgCfg.SkipSchemaInit {
|
||||
pgBroker := mapBroker.(*pgmapbroker.PostgresMapBroker)
|
||||
if schemaErr := pgBroker.EnsureSchema(context.Background()); schemaErr != nil {
|
||||
return fmt.Errorf("error initializing Postgres map broker schema: %w", schemaErr)
|
||||
}
|
||||
}
|
||||
mapBrokerMode = "postgres"
|
||||
default:
|
||||
return fmt.Errorf("unknown map broker type: %s", cfg.MapBroker.Type)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating map broker: %v", err)
|
||||
}
|
||||
event := log.Info().Str("map_broker_type", cfg.MapBroker.Type)
|
||||
if mapBrokerMode != "" {
|
||||
event.Str("map_broker_mode", mapBrokerMode)
|
||||
}
|
||||
event.Msg("initializing map broker")
|
||||
node.SetMapBroker(mapBroker)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user