github.com/project-88388/tendermint-v0.34.14-terra.2@v1.0.0/proxy/multi_app_conn.go (about) 1 package proxy 2 3 import ( 4 "fmt" 5 6 abcicli "github.com/tendermint/tendermint/abci/client" 7 tmlog "github.com/tendermint/tendermint/libs/log" 8 tmos "github.com/tendermint/tendermint/libs/os" 9 "github.com/tendermint/tendermint/libs/service" 10 ) 11 12 const ( 13 connConsensus = "consensus" 14 connMempool = "mempool" 15 connQuery = "query" 16 connSnapshot = "snapshot" 17 ) 18 19 // AppConns is the Tendermint's interface to the application that consists of 20 // multiple connections. 21 type AppConns interface { 22 service.Service 23 24 // Mempool connection 25 Mempool() AppConnMempool 26 // Consensus connection 27 Consensus() AppConnConsensus 28 // Query connection 29 Query() AppConnQuery 30 // Snapshot connection 31 Snapshot() AppConnSnapshot 32 } 33 34 // NewAppConns calls NewMultiAppConn. 35 func NewAppConns(clientCreator ClientCreator) AppConns { 36 return NewMultiAppConn(clientCreator) 37 } 38 39 // multiAppConn implements AppConns. 40 // 41 // A multiAppConn is made of a few appConns and manages their underlying abci 42 // clients. 43 // TODO: on app restart, clients must reboot together 44 type multiAppConn struct { 45 service.BaseService 46 47 consensusConn AppConnConsensus 48 mempoolConn AppConnMempool 49 queryConn AppConnQuery 50 snapshotConn AppConnSnapshot 51 52 consensusConnClient abcicli.Client 53 mempoolConnClient abcicli.Client 54 queryConnClient abcicli.Client 55 snapshotConnClient abcicli.Client 56 57 clientCreator ClientCreator 58 } 59 60 // NewMultiAppConn makes all necessary abci connections to the application. 61 func NewMultiAppConn(clientCreator ClientCreator) AppConns { 62 multiAppConn := &multiAppConn{ 63 clientCreator: clientCreator, 64 } 65 multiAppConn.BaseService = *service.NewBaseService(nil, "multiAppConn", multiAppConn) 66 return multiAppConn 67 } 68 69 func (app *multiAppConn) Mempool() AppConnMempool { 70 return app.mempoolConn 71 } 72 73 func (app *multiAppConn) Consensus() AppConnConsensus { 74 return app.consensusConn 75 } 76 77 func (app *multiAppConn) Query() AppConnQuery { 78 return app.queryConn 79 } 80 81 func (app *multiAppConn) Snapshot() AppConnSnapshot { 82 return app.snapshotConn 83 } 84 85 func (app *multiAppConn) OnStart() error { 86 c, err := app.abciClientFor(connQuery) 87 if err != nil { 88 return err 89 } 90 app.queryConnClient = c 91 app.queryConn = NewAppConnQuery(c) 92 93 c, err = app.abciClientFor(connSnapshot) 94 if err != nil { 95 app.stopAllClients() 96 return err 97 } 98 app.snapshotConnClient = c 99 app.snapshotConn = NewAppConnSnapshot(c) 100 101 c, err = app.abciClientFor(connMempool) 102 if err != nil { 103 app.stopAllClients() 104 return err 105 } 106 app.mempoolConnClient = c 107 app.mempoolConn = NewAppConnMempool(c) 108 109 c, err = app.abciClientFor(connConsensus) 110 if err != nil { 111 app.stopAllClients() 112 return err 113 } 114 app.consensusConnClient = c 115 app.consensusConn = NewAppConnConsensus(c) 116 117 // Kill Tendermint if the ABCI application crashes. 118 go app.killTMOnClientError() 119 120 return nil 121 } 122 123 func (app *multiAppConn) OnStop() { 124 app.stopAllClients() 125 } 126 127 func (app *multiAppConn) killTMOnClientError() { 128 killFn := func(conn string, err error, logger tmlog.Logger) { 129 logger.Error( 130 fmt.Sprintf("%s connection terminated. Did the application crash? Please restart tendermint", conn), 131 "err", err) 132 killErr := tmos.Kill() 133 if killErr != nil { 134 logger.Error("Failed to kill this process - please do so manually", "err", killErr) 135 } 136 } 137 138 select { 139 case <-app.consensusConnClient.Quit(): 140 if err := app.consensusConnClient.Error(); err != nil { 141 killFn(connConsensus, err, app.Logger) 142 } 143 case <-app.mempoolConnClient.Quit(): 144 if err := app.mempoolConnClient.Error(); err != nil { 145 killFn(connMempool, err, app.Logger) 146 } 147 case <-app.queryConnClient.Quit(): 148 if err := app.queryConnClient.Error(); err != nil { 149 killFn(connQuery, err, app.Logger) 150 } 151 case <-app.snapshotConnClient.Quit(): 152 if err := app.snapshotConnClient.Error(); err != nil { 153 killFn(connSnapshot, err, app.Logger) 154 } 155 } 156 } 157 158 func (app *multiAppConn) stopAllClients() { 159 if app.consensusConnClient != nil { 160 if err := app.consensusConnClient.Stop(); err != nil { 161 app.Logger.Error("error while stopping consensus client", "error", err) 162 } 163 } 164 if app.mempoolConnClient != nil { 165 if err := app.mempoolConnClient.Stop(); err != nil { 166 app.Logger.Error("error while stopping mempool client", "error", err) 167 } 168 } 169 if app.queryConnClient != nil { 170 if err := app.queryConnClient.Stop(); err != nil { 171 app.Logger.Error("error while stopping query client", "error", err) 172 } 173 } 174 if app.snapshotConnClient != nil { 175 if err := app.snapshotConnClient.Stop(); err != nil { 176 app.Logger.Error("error while stopping snapshot client", "error", err) 177 } 178 } 179 } 180 181 func (app *multiAppConn) abciClientFor(conn string) (abcicli.Client, error) { 182 c, err := app.clientCreator.NewABCIClient() 183 if err != nil { 184 return nil, fmt.Errorf("error creating ABCI client (%s connection): %w", conn, err) 185 } 186 c.SetLogger(app.Logger.With("module", "abci-client", "connection", conn)) 187 if err := c.Start(); err != nil { 188 return nil, fmt.Errorf("error starting ABCI client (%s connection): %w", conn, err) 189 } 190 return c, nil 191 }