mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-05 04:55:18 +00:00
Closes #5074 Old code does not work when --consensus.create_empty_blocks=false (because it only calls tmos.Kill when ApplyBlock fails). New code is listening ABCI clients for Quit and kills TM process if there were any errors.
184 lines
4.5 KiB
Go
184 lines
4.5 KiB
Go
package proxy
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
abcicli "github.com/tendermint/tendermint/abci/client"
|
|
tmlog "github.com/tendermint/tendermint/libs/log"
|
|
tmos "github.com/tendermint/tendermint/libs/os"
|
|
"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 ClientCreator) 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 abcicli.Client
|
|
mempoolConnClient abcicli.Client
|
|
queryConnClient abcicli.Client
|
|
snapshotConnClient abcicli.Client
|
|
|
|
clientCreator ClientCreator
|
|
}
|
|
|
|
// NewMultiAppConn makes all necessary abci connections to the application.
|
|
func NewMultiAppConn(clientCreator ClientCreator) 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)
|
|
killErr := tmos.Kill()
|
|
if 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 {
|
|
app.consensusConnClient.Stop()
|
|
}
|
|
if app.mempoolConnClient != nil {
|
|
app.mempoolConnClient.Stop()
|
|
}
|
|
if app.queryConnClient != nil {
|
|
app.queryConnClient.Stop()
|
|
}
|
|
if app.snapshotConnClient != nil {
|
|
app.snapshotConnClient.Stop()
|
|
}
|
|
}
|
|
|
|
func (app *multiAppConn) abciClientFor(conn string) (abcicli.Client, error) {
|
|
c, err := app.clientCreator.NewABCIClient()
|
|
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
|
|
}
|