From a2e83e298b3ccc8287a1df2869255dbb1124aa85 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 19 May 2023 10:03:44 +0000 Subject: [PATCH] feat: add Close method for resource cleanup in graceful shutdown (backport #16193) (#16205) Co-authored-by: yihuang Co-authored-by: Julien Robert --- CHANGELOG.md | 1 + baseapp/baseapp.go | 102 +------------------------------------------- server/start.go | 9 ++-- server/types/app.go | 3 ++ 4 files changed, 11 insertions(+), 104 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acbeab398253..a0604a5697e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (gov) [#15979](https://github.com/cosmos/cosmos-sdk/pull/15979) Improve gov error message when failing to convert v1 proposal to v1beta1. * (server) [#16061](https://github.com/cosmos/cosmos-sdk/pull/16061) add comet bootstrap command * (store) [#16067](https://github.com/cosmos/cosmos-sdk/pull/16067) Add local snapshots management commands. +* (baseapp) [#16193](https://github.com/cosmos/cosmos-sdk/pull/16193) Add `Close` method to `BaseApp` for custom app to cleanup resource in graceful shutdown. ### Bug Fixes diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index dcdff62fc7bf..aed91ea68a14 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -1096,107 +1096,7 @@ func makeABCIData(msgResponses []*codectypes.Any) ([]byte, error) { return proto.Marshal(&sdk.TxMsgData{MsgResponses: msgResponses}) } -func createEvents(cdc codec.Codec, events sdk.Events, msg sdk.Msg, reflectMsg protoreflect.Message) (sdk.Events, error) { - eventMsgName := sdk.MsgTypeURL(msg) - msgEvent := sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, eventMsgName)) - - // we set the signer attribute as the sender - signers, err := cdc.GetReflectMsgSigners(reflectMsg) - if err != nil { - return nil, err - } - if len(signers) > 0 && signers[0] != nil { - addrStr, err := cdc.InterfaceRegistry().SigningContext().AddressCodec().BytesToString(signers[0]) - if err != nil { - return nil, err - } - msgEvent = msgEvent.AppendAttributes(sdk.NewAttribute(sdk.AttributeKeySender, addrStr)) - } - - // verify that events have no module attribute set - if _, found := events.GetAttributes(sdk.AttributeKeyModule); !found { - if moduleName := sdk.GetModuleNameFromTypeURL(eventMsgName); moduleName != "" { - msgEvent = msgEvent.AppendAttributes(sdk.NewAttribute(sdk.AttributeKeyModule, moduleName)) - } - } - - return sdk.Events{msgEvent}.AppendEvents(events), nil -} - -// PrepareProposalVerifyTx performs transaction verification when a proposer is -// creating a block proposal during PrepareProposal. Any state committed to the -// PrepareProposal state internally will be discarded. will be -// returned if the transaction cannot be encoded. will be returned if -// the transaction is valid, otherwise will be returned. -func (app *BaseApp) PrepareProposalVerifyTx(tx sdk.Tx) ([]byte, error) { - bz, err := app.txEncoder(tx) - if err != nil { - return nil, err - } - - _, _, _, err = app.runTx(execModePrepareProposal, bz) - if err != nil { - return nil, err - } - - return bz, nil -} - -// ProcessProposalVerifyTx performs transaction verification when receiving a -// block proposal during ProcessProposal. Any state committed to the -// ProcessProposal state internally will be discarded. will be -// returned if the transaction cannot be decoded. will be returned if -// the transaction is valid, otherwise will be returned. -func (app *BaseApp) ProcessProposalVerifyTx(txBz []byte) (sdk.Tx, error) { - tx, err := app.txDecoder(txBz) - if err != nil { - return nil, err - } - - _, _, _, err = app.runTx(execModeProcessProposal, txBz) - if err != nil { - return nil, err - } - - return tx, nil -} - -func (app *BaseApp) TxDecode(txBytes []byte) (sdk.Tx, error) { - return app.txDecoder(txBytes) -} - -func (app *BaseApp) TxEncode(tx sdk.Tx) ([]byte, error) { - return app.txEncoder(tx) -} - // Close is called in start cmd to gracefully cleanup resources. func (app *BaseApp) Close() error { - var errs []error - - // Close app.db (opened by cosmos-sdk/server/start.go call to openDB) - if app.db != nil { - app.logger.Info("Closing application.db") - if err := app.db.Close(); err != nil { - errs = append(errs, err) - } - } - - // Close app.snapshotManager - // - opened when app chains use cosmos-sdk/server/util.go/DefaultBaseappOptions (boilerplate) - // - which calls cosmos-sdk/server/util.go/GetSnapshotStore - // - which is passed to baseapp/options.go/SetSnapshot - // - to set app.snapshotManager = snapshots.NewManager - if app.snapshotManager != nil { - app.logger.Info("Closing snapshots/metadata.db") - if err := app.snapshotManager.Close(); err != nil { - errs = append(errs, err) - } - } - - return errors.Join(errs...) -} - -// GetBaseApp returns the pointer to itself. -func (app *BaseApp) GetBaseApp() *BaseApp { - return app + return nil } diff --git a/server/start.go b/server/start.go index 6aa25ae3ca5d..10d382e1449c 100644 --- a/server/start.go +++ b/server/start.go @@ -262,9 +262,11 @@ func startStandAlone[T types.Application](svrCtx *Context, svrCfg serverconfig.C if err != nil { return err } - // re-assign for making the client available below - // do not use := to avoid shadowing clientCtx - clientCtx = clientCtx.WithClient(rpcclient) + + if err = app.Close(); err != nil { + tmos.Exit(err.Error()) + } + }() // use the provided clientCtx to register the services app.RegisterTxService(clientCtx) @@ -536,6 +538,7 @@ func startApp[T types.Application](svrCtx *Context, appCreator types.AppCreator[ defer func() { if tmNode != nil && tmNode.IsRunning() { _ = tmNode.Stop() + _ = app.Close() } if apiSrv != nil { diff --git a/server/types/app.go b/server/types/app.go index 286bc9dcab9d..73f300989127 100644 --- a/server/types/app.go +++ b/server/types/app.go @@ -57,6 +57,9 @@ type ( // Return the snapshot manager SnapshotManager() *snapshots.Manager + + // Close is called in start cmd to gracefully cleanup resources. + Close() error } // ApplicationQueryService defines an extension of the Application interface