Skip to content

Commit 200f775

Browse files
committed
Merge branch 'develop' into sdp-sep-wallet-registration
# Conflicts: # helmchart/sdp/README.md
2 parents d84ea3a + fad00ad commit 200f775

19 files changed

+265
-30
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- Add configurable database connection pool settings to prevent idle connection buildup in multi-tenant deployments [#932](https://github.com/stellar/stellar-disbursement-platform-backend/pull/932)
12+
13+
### Changed
14+
15+
- Default Max Open Connections per pool changed from 30 to 20 to prevent idle connection buildup in multi-tenant deployments [#932](https://github.com/stellar/stellar-disbursement-platform-backend/pull/932)
16+
917
### Fixed
1018

1119
- Fix HTML validation to allow apostrophes in invitation messages while maintaining security against XSS attacks [#930](https://github.com/stellar/stellar-disbursement-platform-backend/pull/930)
1220

21+
1322
## [5.0.0](https://github.com/stellar/stellar-disbursement-platform-backend/releases/tag/5.0.0) ([diff](https://github.com/stellar/stellar-disbursement-platform-backend/compare/4.1.0...5.0.0))
1423

1524
### Added

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,23 @@ The following environment variables can be used to configure the intervals of th
386386
>Prior to version 3.7.0, background jobs were configured using ENABLE_SCHEDULER=true and EVENT_BROKER_TYPE=NONE.
387387
>This configuration has been deprecated in favor of using EVENT_BROKER_TYPE=SCHEDULER.
388388
389+
### Database connection pool
390+
391+
Tune the per-tenant PostgreSQL connection pool with env vars (defaults shown):
392+
393+
```sh
394+
# Maximum open connections per pool (default: 10)
395+
DB_MAX_OPEN_CONNS=10
396+
# Maximum idle connections retained (default: 0)
397+
DB_MAX_IDLE_CONNS=0
398+
# Close idle connections after N seconds (default: 2)
399+
DB_CONN_MAX_IDLE_TIME_SECONDS=2
400+
# Recycle connections after N seconds (default: 300 = 5 minutes)
401+
DB_CONN_MAX_LIFETIME_SECONDS=300
402+
```
403+
404+
These settings help prevent idle connection buildup across multi-tenant scheduler cycles, especially on constrained databases.
405+
389406
## Wallets
390407

391408
Please check the [Making Your Wallet SDP-Ready](https://docs.stellar.org/stellar-disbursement-platform/making-your-wallet-sdp-ready) section of the Stellar Docs for more information on how to integrate your wallet with the SDP.

cmd/channel_accounts.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,14 @@ func (c *ChannelAccountsCommand) Command(cmdService ChAccCmdServiceInterface) *c
133133
metricsServeOpts.MonitorService = &tssMonitorSvc
134134

135135
// Setup the TSSDBConnectionPool
136-
dbcpOptions := di.DBConnectionPoolOptions{DatabaseURL: globalOptions.DatabaseURL, MonitorService: &tssMonitorSvc}
136+
dbcpOptions := di.DBConnectionPoolOptions{
137+
DatabaseURL: globalOptions.DatabaseURL,
138+
MonitorService: &tssMonitorSvc,
139+
MaxOpenConns: globalOptions.DBPool.DBMaxOpenConns,
140+
MaxIdleConns: globalOptions.DBPool.DBMaxIdleConns,
141+
ConnMaxIdleTimeSeconds: globalOptions.DBPool.DBConnMaxIdleTimeSeconds,
142+
ConnMaxLifetimeSeconds: globalOptions.DBPool.DBConnMaxLifetimeSeconds,
143+
}
137144
c.TSSDBConnectionPool, err = di.NewTSSDBConnectionPool(ctx, dbcpOptions)
138145
if err != nil {
139146
log.Ctx(ctx).Fatalf("Error creating TSS DB connection pool: %v", err)

cmd/db/db.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@ func (c *DatabaseCommand) Command(globalOptions *utils.GlobalOptionsType) *cobra
3333
PersistentPreRun: func(cmd *cobra.Command, args []string) {
3434
utils.PropagatePersistentPreRun(cmd, args)
3535

36-
adminDBConnectionPool, err := di.NewAdminDBConnectionPool(cmd.Context(), di.DBConnectionPoolOptions{DatabaseURL: globalOptions.DatabaseURL})
36+
adminDBConnectionPool, err := di.NewAdminDBConnectionPool(cmd.Context(), di.DBConnectionPoolOptions{
37+
DatabaseURL: globalOptions.DatabaseURL,
38+
MaxOpenConns: globalOptions.DBPool.DBMaxOpenConns,
39+
MaxIdleConns: globalOptions.DBPool.DBMaxIdleConns,
40+
ConnMaxIdleTimeSeconds: globalOptions.DBPool.DBConnMaxIdleTimeSeconds,
41+
ConnMaxLifetimeSeconds: globalOptions.DBPool.DBConnMaxLifetimeSeconds,
42+
})
3743
if err != nil {
3844
log.Ctx(cmd.Context()).Fatalf("getting Admin database connection pool: %v", err)
3945
}

cmd/distribution_accounts.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,13 @@ func (c *DistributionAccountCommand) Command(cmdService DistAccCmdServiceInterfa
5252
}
5353

5454
// Setup the TSSDBConnectionPool
55-
dbcpOptions := di.DBConnectionPoolOptions{DatabaseURL: globalOptions.DatabaseURL}
55+
dbcpOptions := di.DBConnectionPoolOptions{
56+
DatabaseURL: globalOptions.DatabaseURL,
57+
MaxOpenConns: globalOptions.DBPool.DBMaxOpenConns,
58+
MaxIdleConns: globalOptions.DBPool.DBMaxIdleConns,
59+
ConnMaxIdleTimeSeconds: globalOptions.DBPool.DBConnMaxIdleTimeSeconds,
60+
ConnMaxLifetimeSeconds: globalOptions.DBPool.DBConnMaxLifetimeSeconds,
61+
}
5662
c.TSSDBConnectionPool, err = di.NewTSSDBConnectionPool(ctx, dbcpOptions)
5763
if err != nil {
5864
log.Ctx(ctx).Fatalf("Error creating TSS DB connection pool: %v", err)

cmd/serve.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,12 @@ func (c *ServeCommand) Command(serverService ServerServiceInterface, monitorServ
377377
cmdUtils.SchedulerConfigOptions(&schedulerOpts)...,
378378
)
379379

380+
// DB pool tuning options (serve)
381+
configOpts = append(
382+
configOpts,
383+
cmdUtils.DBPoolConfigOptions(&globalOptions.DBPool)...,
384+
)
385+
380386
// bridge integration options
381387
bridgeIntegrationOpts := cmdUtils.BridgeIntegrationOptions{}
382388
configOpts = append(
@@ -436,7 +442,14 @@ func (c *ServeCommand) Command(serverService ServerServiceInterface, monitorServ
436442
ctx := cmd.Context()
437443

438444
// Setup the Admin DB connection pool
439-
dbcpOptions := di.DBConnectionPoolOptions{DatabaseURL: globalOptions.DatabaseURL, MonitorService: monitorService}
445+
dbcpOptions := di.DBConnectionPoolOptions{
446+
DatabaseURL: globalOptions.DatabaseURL,
447+
MonitorService: monitorService,
448+
MaxOpenConns: globalOptions.DBPool.DBMaxOpenConns,
449+
MaxIdleConns: globalOptions.DBPool.DBMaxIdleConns,
450+
ConnMaxIdleTimeSeconds: globalOptions.DBPool.DBConnMaxIdleTimeSeconds,
451+
ConnMaxLifetimeSeconds: globalOptions.DBPool.DBConnMaxLifetimeSeconds,
452+
}
440453
adminDBConnectionPool, err := di.NewAdminDBConnectionPool(ctx, dbcpOptions)
441454
if err != nil {
442455
log.Ctx(ctx).Fatalf("error getting Admin DB connection pool: %v", err)

cmd/tenants.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,13 @@ func (cmd *TenantsCommand) Command() *cobra.Command {
196196
}
197197

198198
func initDBPools(ctx context.Context, dbURL string) (admin, mtn, tss dbpkg.DBConnectionPool, err error) {
199-
opts := di.DBConnectionPoolOptions{DatabaseURL: dbURL}
199+
opts := di.DBConnectionPoolOptions{
200+
DatabaseURL: dbURL,
201+
MaxOpenConns: globalOptions.DBPool.DBMaxOpenConns,
202+
MaxIdleConns: globalOptions.DBPool.DBMaxIdleConns,
203+
ConnMaxIdleTimeSeconds: globalOptions.DBPool.DBConnMaxIdleTimeSeconds,
204+
ConnMaxLifetimeSeconds: globalOptions.DBPool.DBConnMaxLifetimeSeconds,
205+
}
200206
if admin, err = di.NewAdminDBConnectionPool(ctx, opts); err != nil {
201207
return
202208
}

cmd/transaction_submitter.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ func (c *TxSubmitterCommand) Command(submitterService TxSubmitterServiceInterfac
123123
cmdUtils.TransactionSubmitterEngineConfigOptions(&txSubmitterOpts)...,
124124
)
125125

126+
// DB pool tuning options (tss)
127+
configOpts = append(
128+
configOpts,
129+
cmdUtils.DBPoolConfigOptions(&globalOptions.DBPool)...,
130+
)
131+
126132
cmd := &cobra.Command{
127133
Use: "tss",
128134
Short: "Run the Transaction Submission Service",
@@ -153,7 +159,14 @@ func (c *TxSubmitterCommand) Command(submitterService TxSubmitterServiceInterfac
153159
tssOpts.MonitorService = tssMonitorSvc
154160

155161
// Initializing the TSSDBConnectionPool
156-
dbcpOptions := di.DBConnectionPoolOptions{DatabaseURL: globalOptions.DatabaseURL, MonitorService: &tssMonitorSvc}
162+
dbcpOptions := di.DBConnectionPoolOptions{
163+
DatabaseURL: globalOptions.DatabaseURL,
164+
MonitorService: &tssMonitorSvc,
165+
MaxOpenConns: globalOptions.DBPool.DBMaxOpenConns,
166+
MaxIdleConns: globalOptions.DBPool.DBMaxIdleConns,
167+
ConnMaxIdleTimeSeconds: globalOptions.DBPool.DBConnMaxIdleTimeSeconds,
168+
ConnMaxLifetimeSeconds: globalOptions.DBPool.DBConnMaxLifetimeSeconds,
169+
}
157170
tssDBConnectionPool, err := di.NewTSSDBConnectionPool(ctx, dbcpOptions)
158171
if err != nil {
159172
log.Ctx(ctx).Fatalf("error getting TSS DB connection pool: %v", err)

cmd/utils/global_options.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type GlobalOptionsType struct {
1313
Version string
1414
GitCommit string
1515
DatabaseURL string
16+
DBPool DBPoolOptions
1617
BaseURL string
1718
SDPUIBaseURL string
1819
NetworkPassphrase string

cmd/utils/shared_config_options.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/stellar/go/support/config"
1111
"github.com/stellar/go/txnbuild"
1212

13+
"github.com/stellar/stellar-disbursement-platform-backend/db"
1314
"github.com/stellar/stellar-disbursement-platform-backend/internal/crashtracker"
1415
di "github.com/stellar/stellar-disbursement-platform-backend/internal/dependencyinjection"
1516
"github.com/stellar/stellar-disbursement-platform-backend/internal/message"
@@ -19,6 +20,52 @@ import (
1920
"github.com/stellar/stellar-disbursement-platform-backend/stellar-multitenant/pkg/tenant"
2021
)
2122

23+
// DBPoolOptions contains tunables for the PostgreSQL connection pool.
24+
type DBPoolOptions struct {
25+
DBMaxOpenConns int
26+
DBMaxIdleConns int
27+
DBConnMaxIdleTimeSeconds int
28+
DBConnMaxLifetimeSeconds int
29+
}
30+
31+
// DBPoolConfigOptions returns config options for tuning the DB connection pool.
32+
func DBPoolConfigOptions(opts *DBPoolOptions) []*config.ConfigOption {
33+
return []*config.ConfigOption{
34+
{
35+
Name: "db-max-open-conns",
36+
Usage: "Maximum number of open DB connections per pool",
37+
OptType: types.Int,
38+
ConfigKey: &opts.DBMaxOpenConns,
39+
FlagDefault: db.DefaultDBPoolConfig.MaxOpenConns,
40+
Required: false,
41+
},
42+
{
43+
Name: "db-max-idle-conns",
44+
Usage: "Maximum number of idle DB connections retained per pool",
45+
OptType: types.Int,
46+
ConfigKey: &opts.DBMaxIdleConns,
47+
FlagDefault: db.DefaultDBPoolConfig.MaxIdleConns,
48+
Required: false,
49+
},
50+
{
51+
Name: "db-conn-max-idle-time-seconds",
52+
Usage: "Maximum idle time in seconds before a connection is closed",
53+
OptType: types.Int,
54+
ConfigKey: &opts.DBConnMaxIdleTimeSeconds,
55+
FlagDefault: db.DefaultConnMaxIdleTimeSeconds,
56+
Required: false,
57+
},
58+
{
59+
Name: "db-conn-max-lifetime-seconds",
60+
Usage: "Maximum lifetime in seconds for a single connection",
61+
OptType: types.Int,
62+
ConfigKey: &opts.DBConnMaxLifetimeSeconds,
63+
FlagDefault: db.DefaultConnMaxLifetimeSeconds,
64+
Required: false,
65+
},
66+
}
67+
}
68+
2269
// TwilioConfigOptions returns the config options for Twilio. Relevant for loading configs needed for the messenger type(s): `TWILIO_*`.
2370
func TwilioConfigOptions(opts *message.MessengerOptions) []*config.ConfigOption {
2471
return []*config.ConfigOption{

0 commit comments

Comments
 (0)