Commit 0d4936e7 authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #7064 from ethereum-optimism/indexer.healthz

feat(indexer): index service /healthz endpoint
parents 7c762e79 7c0231de
...@@ -38,7 +38,7 @@ func runIndexer(ctx *cli.Context) error { ...@@ -38,7 +38,7 @@ func runIndexer(ctx *cli.Context) error {
} }
defer db.Close() defer db.Close()
indexer, err := indexer.NewIndexer(log, db, cfg.Chain, cfg.RPCs, cfg.Metrics) indexer, err := indexer.NewIndexer(log, db, cfg.Chain, cfg.RPCs, cfg.HTTPServer, cfg.MetricsServer)
if err != nil { if err != nil {
log.Error("failed to create indexer", "err", err) log.Error("failed to create indexer", "err", err)
return err return err
...@@ -63,7 +63,7 @@ func runApi(ctx *cli.Context) error { ...@@ -63,7 +63,7 @@ func runApi(ctx *cli.Context) error {
defer db.Close() defer db.Close()
api := api.NewApi(log, db.BridgeTransfers) api := api.NewApi(log, db.BridgeTransfers)
return api.Listen(ctx.Context, cfg.API.Port) return api.Listen(ctx.Context, cfg.HTTPServer.Port)
} }
func runAll(ctx *cli.Context) error { func runAll(ctx *cli.Context) error {
......
...@@ -20,11 +20,11 @@ const ( ...@@ -20,11 +20,11 @@ const (
// Config represents the `indexer.toml` file used to configure the indexer // Config represents the `indexer.toml` file used to configure the indexer
type Config struct { type Config struct {
Chain ChainConfig `toml:"chain"` Chain ChainConfig `toml:"chain"`
RPCs RPCsConfig `toml:"rpcs"` RPCs RPCsConfig `toml:"rpcs"`
DB DBConfig `toml:"db"` DB DBConfig `toml:"db"`
API APIConfig `toml:"api"` HTTPServer ServerConfig `toml:"http"`
Metrics MetricsConfig `toml:"metrics"` MetricsServer ServerConfig `toml:"metrics"`
} }
// fetch this via onchain config from RPCsConfig and remove from config in future // fetch this via onchain config from RPCsConfig and remove from config in future
...@@ -96,14 +96,8 @@ type DBConfig struct { ...@@ -96,14 +96,8 @@ type DBConfig struct {
Password string `toml:"password"` Password string `toml:"password"`
} }
// APIConfig configures the API server // Configures the a server
type APIConfig struct { type ServerConfig struct {
Host string `toml:"host"`
Port int `toml:"port"`
}
// MetricsConfig configures the metrics server
type MetricsConfig struct {
Host string `toml:"host"` Host string `toml:"host"`
Port int `toml:"port"` Port int `toml:"port"`
} }
......
...@@ -31,9 +31,9 @@ func TestLoadConfig(t *testing.T) { ...@@ -31,9 +31,9 @@ func TestLoadConfig(t *testing.T) {
port = 5432 port = 5432
user = "postgres" user = "postgres"
password = "postgres" password = "postgres"
name = "indexer" name = "indexer"
[api] [http]
host = "127.0.0.1" host = "127.0.0.1"
port = 8080 port = 8080
...@@ -65,10 +65,10 @@ func TestLoadConfig(t *testing.T) { ...@@ -65,10 +65,10 @@ func TestLoadConfig(t *testing.T) {
require.Equal(t, conf.DB.User, "postgres") require.Equal(t, conf.DB.User, "postgres")
require.Equal(t, conf.DB.Password, "postgres") require.Equal(t, conf.DB.Password, "postgres")
require.Equal(t, conf.DB.Name, "indexer") require.Equal(t, conf.DB.Name, "indexer")
require.Equal(t, conf.API.Host, "127.0.0.1") require.Equal(t, conf.HTTPServer.Host, "127.0.0.1")
require.Equal(t, conf.API.Port, 8080) require.Equal(t, conf.HTTPServer.Port, 8080)
require.Equal(t, conf.Metrics.Host, "127.0.0.1") require.Equal(t, conf.MetricsServer.Host, "127.0.0.1")
require.Equal(t, conf.Metrics.Port, 7300) require.Equal(t, conf.MetricsServer.Port, 7300)
} }
func TestLoadConfig_WithoutPreset(t *testing.T) { func TestLoadConfig_WithoutPreset(t *testing.T) {
......
...@@ -82,10 +82,8 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite { ...@@ -82,10 +82,8 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite {
L1StandardBridgeProxy: opCfg.L1Deployments.L1StandardBridgeProxy, L1StandardBridgeProxy: opCfg.L1Deployments.L1StandardBridgeProxy,
}, },
}, },
Metrics: config.MetricsConfig{ HTTPServer: config.ServerConfig{Host: "127.0.0.1", Port: 0},
Host: "127.0.0.1", MetricsServer: config.ServerConfig{Host: "127.0.0.1", Port: 0},
Port: 0,
},
} }
db, err := database.NewDB(indexerCfg.DB) db, err := database.NewDB(indexerCfg.DB)
...@@ -93,7 +91,7 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite { ...@@ -93,7 +91,7 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite {
t.Cleanup(func() { db.Close() }) t.Cleanup(func() { db.Close() })
indexerLog := testlog.Logger(t, log.LvlInfo).New("role", "indexer") indexerLog := testlog.Logger(t, log.LvlInfo).New("role", "indexer")
indexer, err := indexer.NewIndexer(indexerLog, db, indexerCfg.Chain, indexerCfg.RPCs, indexerCfg.Metrics) indexer, err := indexer.NewIndexer(indexerLog, db, indexerCfg.Chain, indexerCfg.RPCs, indexerCfg.HTTPServer, indexerCfg.MetricsServer)
require.NoError(t, err) require.NoError(t, err)
indexerCtx, indexerStop := context.WithCancel(context.Background()) indexerCtx, indexerStop := context.WithCancel(context.Background())
......
...@@ -4,10 +4,15 @@ import ( ...@@ -4,10 +4,15 @@ import (
"context" "context"
"fmt" "fmt"
"math/big" "math/big"
"net/http"
"runtime/debug" "runtime/debug"
"sync" "sync"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/ethereum-optimism/optimism/indexer/config" "github.com/ethereum-optimism/optimism/indexer/config"
...@@ -15,6 +20,7 @@ import ( ...@@ -15,6 +20,7 @@ import (
"github.com/ethereum-optimism/optimism/indexer/etl" "github.com/ethereum-optimism/optimism/indexer/etl"
"github.com/ethereum-optimism/optimism/indexer/node" "github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/indexer/processors" "github.com/ethereum-optimism/optimism/indexer/processors"
"github.com/ethereum-optimism/optimism/op-service/httputil"
"github.com/ethereum-optimism/optimism/op-service/metrics" "github.com/ethereum-optimism/optimism/op-service/metrics"
) )
...@@ -24,7 +30,8 @@ type Indexer struct { ...@@ -24,7 +30,8 @@ type Indexer struct {
log log.Logger log log.Logger
db *database.DB db *database.DB
metricsConfig config.MetricsConfig httpConfig config.ServerConfig
metricsConfig config.ServerConfig
metricsRegistry *prometheus.Registry metricsRegistry *prometheus.Registry
L1ETL *etl.L1ETL L1ETL *etl.L1ETL
...@@ -33,7 +40,14 @@ type Indexer struct { ...@@ -33,7 +40,14 @@ type Indexer struct {
} }
// NewIndexer initializes an instance of the Indexer // NewIndexer initializes an instance of the Indexer
func NewIndexer(logger log.Logger, db *database.DB, chainConfig config.ChainConfig, rpcsConfig config.RPCsConfig, metricsConfig config.MetricsConfig) (*Indexer, error) { func NewIndexer(
log log.Logger,
db *database.DB,
chainConfig config.ChainConfig,
rpcsConfig config.RPCsConfig,
httpConfig config.ServerConfig,
metricsConfig config.ServerConfig,
) (*Indexer, error) {
metricsRegistry := metrics.NewRegistry() metricsRegistry := metrics.NewRegistry()
// L1 // L1
...@@ -47,7 +61,7 @@ func NewIndexer(logger log.Logger, db *database.DB, chainConfig config.ChainConf ...@@ -47,7 +61,7 @@ func NewIndexer(logger log.Logger, db *database.DB, chainConfig config.ChainConf
ConfirmationDepth: big.NewInt(int64(chainConfig.L1ConfirmationDepth)), ConfirmationDepth: big.NewInt(int64(chainConfig.L1ConfirmationDepth)),
StartHeight: big.NewInt(int64(chainConfig.L1StartingHeight)), StartHeight: big.NewInt(int64(chainConfig.L1StartingHeight)),
} }
l1Etl, err := etl.NewL1ETL(l1Cfg, logger, db, etl.NewMetrics(metricsRegistry, "l1"), l1EthClient, chainConfig.L1Contracts) l1Etl, err := etl.NewL1ETL(l1Cfg, log, db, etl.NewMetrics(metricsRegistry, "l1"), l1EthClient, chainConfig.L1Contracts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -62,21 +76,22 @@ func NewIndexer(logger log.Logger, db *database.DB, chainConfig config.ChainConf ...@@ -62,21 +76,22 @@ func NewIndexer(logger log.Logger, db *database.DB, chainConfig config.ChainConf
HeaderBufferSize: chainConfig.L2HeaderBufferSize, HeaderBufferSize: chainConfig.L2HeaderBufferSize,
ConfirmationDepth: big.NewInt(int64(chainConfig.L2ConfirmationDepth)), ConfirmationDepth: big.NewInt(int64(chainConfig.L2ConfirmationDepth)),
} }
l2Etl, err := etl.NewL2ETL(l2Cfg, logger, db, etl.NewMetrics(metricsRegistry, "l2"), l2EthClient) l2Etl, err := etl.NewL2ETL(l2Cfg, log, db, etl.NewMetrics(metricsRegistry, "l2"), l2EthClient)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Bridge // Bridge
bridgeProcessor, err := processors.NewBridgeProcessor(logger, db, l1Etl, chainConfig) bridgeProcessor, err := processors.NewBridgeProcessor(log, db, l1Etl, chainConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
indexer := &Indexer{ indexer := &Indexer{
log: logger, log: log,
db: db, db: db,
httpConfig: httpConfig,
metricsConfig: metricsConfig, metricsConfig: metricsConfig,
metricsRegistry: metricsRegistry, metricsRegistry: metricsRegistry,
...@@ -88,6 +103,23 @@ func NewIndexer(logger log.Logger, db *database.DB, chainConfig config.ChainConf ...@@ -88,6 +103,23 @@ func NewIndexer(logger log.Logger, db *database.DB, chainConfig config.ChainConf
return indexer, nil return indexer, nil
} }
func (i *Indexer) startHttpServer(ctx context.Context) error {
i.log.Info("starting http server...", "port", i.httpConfig.Host)
r := chi.NewRouter()
r.Use(middleware.Heartbeat("/healthz"))
server := http.Server{Addr: fmt.Sprintf("%s:%d", i.httpConfig.Host, i.httpConfig.Port), Handler: r}
err := httputil.ListenAndServeContext(ctx, &server)
if err != nil {
i.log.Error("http server stopped", "err", err)
} else {
i.log.Info("http server stopped")
}
return err
}
func (i *Indexer) startMetricsServer(ctx context.Context) error { func (i *Indexer) startMetricsServer(ctx context.Context) error {
i.log.Info("starting metrics server...", "port", i.metricsConfig.Port) i.log.Info("starting metrics server...", "port", i.metricsConfig.Port)
err := metrics.ListenAndServe(ctx, i.metricsRegistry, i.metricsConfig.Host, i.metricsConfig.Port) err := metrics.ListenAndServe(ctx, i.metricsRegistry, i.metricsConfig.Host, i.metricsConfig.Port)
...@@ -103,7 +135,7 @@ func (i *Indexer) startMetricsServer(ctx context.Context) error { ...@@ -103,7 +135,7 @@ func (i *Indexer) startMetricsServer(ctx context.Context) error {
// Start starts the indexing service on L1 and L2 chains // Start starts the indexing service on L1 and L2 chains
func (i *Indexer) Run(ctx context.Context) error { func (i *Indexer) Run(ctx context.Context) error {
var wg sync.WaitGroup var wg sync.WaitGroup
errCh := make(chan error, 4) errCh := make(chan error, 5)
// if any goroutine halts, we stop the entire indexer // if any goroutine halts, we stop the entire indexer
processCtx, processCancel := context.WithCancel(ctx) processCtx, processCancel := context.WithCancel(ctx)
...@@ -130,6 +162,7 @@ func (i *Indexer) Run(ctx context.Context) error { ...@@ -130,6 +162,7 @@ func (i *Indexer) Run(ctx context.Context) error {
runProcess(i.L2ETL.Start) runProcess(i.L2ETL.Start)
runProcess(i.BridgeProcessor.Start) runProcess(i.BridgeProcessor.Start)
runProcess(i.startMetricsServer) runProcess(i.startMetricsServer)
runProcess(i.startHttpServer)
wg.Wait() wg.Wait()
err := <-errCh err := <-errCh
......
...@@ -28,7 +28,7 @@ user = "db_username" ...@@ -28,7 +28,7 @@ user = "db_username"
password = "db_password" password = "db_password"
name = "db_name" name = "db_name"
[api] [http]
host = "127.0.0.1" host = "127.0.0.1"
port = 8080 port = 8080
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment