github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/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 app.consensusConnClient.Stop() 161 } 162 if app.mempoolConnClient != nil { 163 app.mempoolConnClient.Stop() 164 } 165 if app.queryConnClient != nil { 166 app.queryConnClient.Stop() 167 } 168 if app.snapshotConnClient != nil { 169 app.snapshotConnClient.Stop() 170 } 171 } 172 173 func (app *multiAppConn) abciClientFor(conn string) (abcicli.Client, error) { 174 c, err := app.clientCreator.NewABCIClient() 175 if err != nil { 176 return nil, fmt.Errorf("error creating ABCI client (%s connection): %w", conn, err) 177 } 178 c.SetLogger(app.Logger.With("module", "abci-client", "connection", conn)) 179 if err := c.Start(); err != nil { 180 return nil, fmt.Errorf("error starting ABCI client (%s connection): %w", conn, err) 181 } 182 return c, nil 183 }