You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
4.5 KiB

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