- package proxy
-
- import (
- "fmt"
- "os"
- "syscall"
-
- abciclient "github.com/tendermint/tendermint/abci/client"
- tmlog "github.com/tendermint/tendermint/libs/log"
- "github.com/tendermint/tendermint/libs/service"
- )
-
- const (
- connConsensus = "consensus"
- connMempool = "mempool"
- connQuery = "query"
- connSnapshot = "snapshot"
- )
-
- // AppConns is the Tendermint's interface to the application that consists of
- // multiple connections.
- type AppConns interface {
- service.Service
-
- // Mempool connection
- Mempool() AppConnMempool
- // Consensus connection
- Consensus() AppConnConsensus
- // Query connection
- Query() AppConnQuery
- // Snapshot connection
- Snapshot() AppConnSnapshot
- }
-
- // NewAppConns calls NewMultiAppConn.
- func NewAppConns(clientCreator abciclient.Creator) AppConns {
- return NewMultiAppConn(clientCreator)
- }
-
- // multiAppConn implements AppConns.
- //
- // A multiAppConn is made of a few appConns and manages their underlying abci
- // clients.
- // TODO: on app restart, clients must reboot together
- type multiAppConn struct {
- service.BaseService
-
- consensusConn AppConnConsensus
- mempoolConn AppConnMempool
- queryConn AppConnQuery
- snapshotConn AppConnSnapshot
-
- consensusConnClient abciclient.Client
- mempoolConnClient abciclient.Client
- queryConnClient abciclient.Client
- snapshotConnClient abciclient.Client
-
- clientCreator abciclient.Creator
- }
-
- // NewMultiAppConn makes all necessary abci connections to the application.
- func NewMultiAppConn(clientCreator abciclient.Creator) AppConns {
- multiAppConn := &multiAppConn{
- clientCreator: clientCreator,
- }
- multiAppConn.BaseService = *service.NewBaseService(nil, "multiAppConn", multiAppConn)
- return multiAppConn
- }
-
- func (app *multiAppConn) Mempool() AppConnMempool {
- return app.mempoolConn
- }
-
- func (app *multiAppConn) Consensus() AppConnConsensus {
- return app.consensusConn
- }
-
- func (app *multiAppConn) Query() AppConnQuery {
- return app.queryConn
- }
-
- func (app *multiAppConn) Snapshot() AppConnSnapshot {
- return app.snapshotConn
- }
-
- func (app *multiAppConn) OnStart() error {
- c, err := app.abciClientFor(connQuery)
- if err != nil {
- return err
- }
- app.queryConnClient = c
- app.queryConn = NewAppConnQuery(c)
-
- c, err = app.abciClientFor(connSnapshot)
- if err != nil {
- app.stopAllClients()
- return err
- }
- app.snapshotConnClient = c
- app.snapshotConn = NewAppConnSnapshot(c)
-
- c, err = app.abciClientFor(connMempool)
- if err != nil {
- app.stopAllClients()
- return err
- }
- app.mempoolConnClient = c
- app.mempoolConn = NewAppConnMempool(c)
-
- c, err = app.abciClientFor(connConsensus)
- if err != nil {
- app.stopAllClients()
- return err
- }
- app.consensusConnClient = c
- app.consensusConn = NewAppConnConsensus(c)
-
- // Kill Tendermint if the ABCI application crashes.
- go app.killTMOnClientError()
-
- return nil
- }
-
- func (app *multiAppConn) OnStop() {
- app.stopAllClients()
- }
-
- func (app *multiAppConn) killTMOnClientError() {
- killFn := func(conn string, err error, logger tmlog.Logger) {
- logger.Error(
- fmt.Sprintf("%s connection terminated. Did the application crash? Please restart tendermint", conn),
- "err", err)
- if killErr := kill(); killErr != nil {
- logger.Error("Failed to kill this process - please do so manually", "err", killErr)
- }
- }
-
- select {
- case <-app.consensusConnClient.Quit():
- if err := app.consensusConnClient.Error(); err != nil {
- killFn(connConsensus, err, app.Logger)
- }
- case <-app.mempoolConnClient.Quit():
- if err := app.mempoolConnClient.Error(); err != nil {
- killFn(connMempool, err, app.Logger)
- }
- case <-app.queryConnClient.Quit():
- if err := app.queryConnClient.Error(); err != nil {
- killFn(connQuery, err, app.Logger)
- }
- case <-app.snapshotConnClient.Quit():
- if err := app.snapshotConnClient.Error(); err != nil {
- killFn(connSnapshot, err, app.Logger)
- }
- }
- }
-
- func (app *multiAppConn) stopAllClients() {
- if app.consensusConnClient != nil {
- if err := app.consensusConnClient.Stop(); err != nil {
- app.Logger.Error("error while stopping consensus client", "error", err)
- }
- }
- if app.mempoolConnClient != nil {
- if err := app.mempoolConnClient.Stop(); err != nil {
- app.Logger.Error("error while stopping mempool client", "error", err)
- }
- }
- if app.queryConnClient != nil {
- if err := app.queryConnClient.Stop(); err != nil {
- app.Logger.Error("error while stopping query client", "error", err)
- }
- }
- if app.snapshotConnClient != nil {
- if err := app.snapshotConnClient.Stop(); err != nil {
- app.Logger.Error("error while stopping snapshot client", "error", err)
- }
- }
- }
-
- func (app *multiAppConn) abciClientFor(conn string) (abciclient.Client, error) {
- c, err := app.clientCreator()
- if err != nil {
- return nil, fmt.Errorf("error creating ABCI client (%s connection): %w", conn, err)
- }
- c.SetLogger(app.Logger.With("module", "abci-client", "connection", conn))
- if err := c.Start(); err != nil {
- return nil, fmt.Errorf("error starting ABCI client (%s connection): %w", conn, err)
- }
- return c, nil
- }
-
- func kill() error {
- p, err := os.FindProcess(os.Getpid())
- if err != nil {
- return err
- }
-
- return p.Signal(syscall.SIGTERM)
- }
|