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.

200 lines
5.0 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. "os"
  5. "syscall"
  6. abciclient "github.com/tendermint/tendermint/abci/client"
  7. tmlog "github.com/tendermint/tendermint/libs/log"
  8. "github.com/tendermint/tendermint/libs/service"
  9. )
  10. const (
  11. connConsensus = "consensus"
  12. connMempool = "mempool"
  13. connQuery = "query"
  14. connSnapshot = "snapshot"
  15. )
  16. // AppConns is the Tendermint's interface to the application that consists of
  17. // multiple connections.
  18. type AppConns interface {
  19. service.Service
  20. // Mempool connection
  21. Mempool() AppConnMempool
  22. // Consensus connection
  23. Consensus() AppConnConsensus
  24. // Query connection
  25. Query() AppConnQuery
  26. // Snapshot connection
  27. Snapshot() AppConnSnapshot
  28. }
  29. // NewAppConns calls NewMultiAppConn.
  30. func NewAppConns(clientCreator abciclient.Creator) AppConns {
  31. return NewMultiAppConn(clientCreator)
  32. }
  33. // multiAppConn implements AppConns.
  34. //
  35. // A multiAppConn is made of a few appConns and manages their underlying abci
  36. // clients.
  37. // TODO: on app restart, clients must reboot together
  38. type multiAppConn struct {
  39. service.BaseService
  40. consensusConn AppConnConsensus
  41. mempoolConn AppConnMempool
  42. queryConn AppConnQuery
  43. snapshotConn AppConnSnapshot
  44. consensusConnClient abciclient.Client
  45. mempoolConnClient abciclient.Client
  46. queryConnClient abciclient.Client
  47. snapshotConnClient abciclient.Client
  48. clientCreator abciclient.Creator
  49. }
  50. // NewMultiAppConn makes all necessary abci connections to the application.
  51. func NewMultiAppConn(clientCreator abciclient.Creator) AppConns {
  52. multiAppConn := &multiAppConn{
  53. clientCreator: clientCreator,
  54. }
  55. multiAppConn.BaseService = *service.NewBaseService(nil, "multiAppConn", multiAppConn)
  56. return multiAppConn
  57. }
  58. func (app *multiAppConn) Mempool() AppConnMempool {
  59. return app.mempoolConn
  60. }
  61. func (app *multiAppConn) Consensus() AppConnConsensus {
  62. return app.consensusConn
  63. }
  64. func (app *multiAppConn) Query() AppConnQuery {
  65. return app.queryConn
  66. }
  67. func (app *multiAppConn) Snapshot() AppConnSnapshot {
  68. return app.snapshotConn
  69. }
  70. func (app *multiAppConn) OnStart() error {
  71. c, err := app.abciClientFor(connQuery)
  72. if err != nil {
  73. return err
  74. }
  75. app.queryConnClient = c
  76. app.queryConn = NewAppConnQuery(c)
  77. c, err = app.abciClientFor(connSnapshot)
  78. if err != nil {
  79. app.stopAllClients()
  80. return err
  81. }
  82. app.snapshotConnClient = c
  83. app.snapshotConn = NewAppConnSnapshot(c)
  84. c, err = app.abciClientFor(connMempool)
  85. if err != nil {
  86. app.stopAllClients()
  87. return err
  88. }
  89. app.mempoolConnClient = c
  90. app.mempoolConn = NewAppConnMempool(c)
  91. c, err = app.abciClientFor(connConsensus)
  92. if err != nil {
  93. app.stopAllClients()
  94. return err
  95. }
  96. app.consensusConnClient = c
  97. app.consensusConn = NewAppConnConsensus(c)
  98. // Kill Tendermint if the ABCI application crashes.
  99. go app.killTMOnClientError()
  100. return nil
  101. }
  102. func (app *multiAppConn) OnStop() {
  103. app.stopAllClients()
  104. }
  105. func (app *multiAppConn) killTMOnClientError() {
  106. killFn := func(conn string, err error, logger tmlog.Logger) {
  107. logger.Error(
  108. fmt.Sprintf("%s connection terminated. Did the application crash? Please restart tendermint", conn),
  109. "err", err)
  110. if killErr := kill(); 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. if err := app.consensusConnClient.Stop(); err != nil {
  136. app.Logger.Error("error while stopping consensus client", "error", err)
  137. }
  138. }
  139. if app.mempoolConnClient != nil {
  140. if err := app.mempoolConnClient.Stop(); err != nil {
  141. app.Logger.Error("error while stopping mempool client", "error", err)
  142. }
  143. }
  144. if app.queryConnClient != nil {
  145. if err := app.queryConnClient.Stop(); err != nil {
  146. app.Logger.Error("error while stopping query client", "error", err)
  147. }
  148. }
  149. if app.snapshotConnClient != nil {
  150. if err := app.snapshotConnClient.Stop(); err != nil {
  151. app.Logger.Error("error while stopping snapshot client", "error", err)
  152. }
  153. }
  154. }
  155. func (app *multiAppConn) abciClientFor(conn string) (abciclient.Client, error) {
  156. c, err := app.clientCreator()
  157. if err != nil {
  158. return nil, fmt.Errorf("error creating ABCI client (%s connection): %w", conn, err)
  159. }
  160. c.SetLogger(app.Logger.With("module", "abci-client", "connection", conn))
  161. if err := c.Start(); err != nil {
  162. return nil, fmt.Errorf("error starting ABCI client (%s connection): %w", conn, err)
  163. }
  164. return c, nil
  165. }
  166. func kill() error {
  167. p, err := os.FindProcess(os.Getpid())
  168. if err != nil {
  169. return err
  170. }
  171. return p.Signal(syscall.SIGTERM)
  172. }