github.com/wfusion/gofusion@v1.1.14/common/infra/drivers/mongo/mongo.go (about) 1 package mongo 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 "time" 8 9 "go.mongodb.org/mongo-driver/mongo" 10 "go.mongodb.org/mongo-driver/mongo/options" 11 12 "github.com/wfusion/gofusion/common/constant" 13 "github.com/wfusion/gofusion/common/utils" 14 ) 15 16 // Option 17 //nolint: revive // mongo options comments too long issue 18 type Option struct { 19 DB string `yaml:"db" json:"db" toml:"db"` 20 AuthDB string `yaml:"auth_db" json:"auth_db" toml:"auth_db" default:"admin"` 21 User string `yaml:"user" json:"user" toml:"user"` 22 Password string `yaml:"password" json:"password" toml:"password" encrypted:""` 23 Endpoints []string `yaml:"endpoints" json:"endpoints" toml:"endpoints"` 24 25 // Timeout specifies the amount of time that a single operation run on this Client can execute before returning an error. 26 // The deadline of any operation run through the Client will be honored above any Timeout set on the Client; Timeout will only 27 // be honored if there is no deadline on the operation Context. Timeout can also be set through the "timeoutMS" URI option 28 // (e.g. "timeoutMS=1000"). The default value is nil, meaning operations do not inherit a timeout from the Client. 29 // 30 // If any Timeout is set (even 0) on the Client, the values of MaxTime on operation options, TransactionOptions.MaxCommitTime and 31 // SessionOptions.DefaultMaxCommitTime will be ignored. Setting Timeout and SocketTimeout or writeConcern.wTimeout will result 32 // in undefined behavior. 33 // 34 // NOTE(benjirewis): SetTimeout represents unstable, provisional API. The behavior of the driver when a Timeout is specified is 35 // subject to change. 36 Timeout string `yaml:"timeout" json:"timeout" toml:"timeout" default:"5s"` 37 // ConnTimeout specifies a timeout that is used for creating connections to the server. If a custom Dialer is 38 // specified through SetDialer, this option must not be used. This can be set through ApplyURI with the 39 // "connectTimeoutMS" (e.g "connectTimeoutMS=30") option. If set to 0, no timeout will be used. The default is 30 40 // seconds. 41 ConnTimeout string `yaml:"conn_timeout" json:"conn_timeout" toml:"conn_timeout" default:"30s"` 42 // SocketTimeout specifies the timeout to be used for the Client's socket reads and writes. 43 // 44 // NOTE(benjirewis): SocketTimeout will be deprecated in a future release. The more general Timeout option 45 // may be used in its place to control the amount of time that a single operation can run before returning 46 // an error. Setting SocketTimeout and Timeout on a single client will result in undefined behavior. 47 SocketTimeout string `yaml:"socket_timeout" json:"socket_timeout" toml:"socket_timeout" default:"5s"` 48 // HeartbeatInterval specifies the amount of time to wait between periodic background server checks. This can also be 49 // set through the "heartbeatIntervalMS" URI option (e.g. "heartbeatIntervalMS=10000"). The default is 10 seconds. 50 HeartbeatInterval string `yaml:"heartbeat_interval" json:"heartbeat_interval" toml:"heartbeat_interval" default:"10s"` 51 52 // MaxConnecting specifies the maximum number of connections a connection pool may establish simultaneously. This can 53 // also be set through the "maxConnecting" URI option (e.g. "maxConnecting=2"). If this is 0, the default is used. The 54 // default is 2. Values greater than 100 are not recommended. 55 MaxConnecting uint64 `yaml:"max_connecting" json:"max_connecting" toml:"max_connecting" default:"2"` 56 // MinPoolSize specifies the minimum number of connections allowed in the driver's connection pool to each server. If 57 // this is non-zero, each server's pool will be maintained in the background to ensure that the size does not fall below 58 // the minimum. This can also be set through the "minPoolSize" URI option (e.g. "minPoolSize=100"). The default is 0. 59 MinPoolSize uint64 `yaml:"min_pool_size" json:"min_pool_size" toml:"min_pool_size"` 60 // MaxPoolSize specifies that maximum number of connections allowed in the driver's connection pool to each server. 61 // Requests to a server will block if this maximum is reached. This can also be set through the "maxPoolSize" URI option 62 // (e.g. "maxPoolSize=100"). If this is 0, maximum connection pool size is not limited. The default is 100. 63 MaxPoolSize uint64 `yaml:"max_pool_size" json:"max_pool_size" toml:"max_pool_size" default:"100"` 64 // MaxConnIdleTime specifies the maximum amount of time that a connection will remain idle in a connection pool 65 // before it is removed from the pool and closed. This can also be set through the "maxIdleTimeMS" URI option (e.g. 66 // "maxIdleTimeMS=10000"). The default is 0, meaning a connection can remain unused indefinitely. 67 MaxConnIdleTime string `yaml:"max_conn_idle_time" json:"max_conn_idle_time" toml:"max_conn_idle_time" default:"10s"` 68 69 // RetryWrites specifies whether supported write operations should be retried once on certain errors, such as network 70 // errors. 71 // 72 // Supported operations are InsertOne, UpdateOne, ReplaceOne, DeleteOne, FindOneAndDelete, FindOneAndReplace, 73 // FindOneAndDelete, InsertMany, and BulkWrite. Note that BulkWrite requests must not include UpdateManyModel or 74 // DeleteManyModel instances to be considered retryable. Unacknowledged writes will not be retried, even if this option 75 // is set to true. 76 // 77 // This option requires server version >= 3.6 and a replica set or sharded cluster and will be ignored for any other 78 // cluster type. This can also be set through the "retryWrites" URI option (e.g. "retryWrites=true"). The default is 79 // true. 80 RetryWrites bool `yaml:"retry_writes" json:"retry_writes" toml:"retry_writes" default:"true"` 81 82 // SetRetryReads specifies whether supported read operations should be retried once on certain errors, such as network 83 // errors. 84 // 85 // Supported operations are Find, FindOne, Aggregate without a $out stage, Distinct, CountDocuments, 86 // EstimatedDocumentCount, Watch (for Client, Database, and Collection), ListCollections, and ListDatabases. Note that 87 // operations run through RunCommand are not retried. 88 // 89 // This option requires server version >= 3.6 and driver version >= 1.1.0. The default is true. 90 RetryReads bool `yaml:"retry_reads" json:"retry_reads" toml:"retry_reads" default:"true"` 91 } 92 93 var Default Dialect = new(defaultDialect) 94 95 type defaultDialect struct{} 96 97 func (d *defaultDialect) New(ctx context.Context, option Option, opts ...utils.OptionExtender) (cli *Mongo, err error) { 98 opt := options.Client().ApplyURI(d.parseOption(option)) 99 opt.SetRetryReads(option.RetryReads) 100 opt.SetRetryWrites(option.RetryWrites) 101 d.wrapDurationSetter(option.Timeout, func(du time.Duration) { opt.SetTimeout(du) }) 102 d.wrapDurationSetter(option.ConnTimeout, func(du time.Duration) { opt.SetConnectTimeout(du) }) 103 d.wrapDurationSetter(option.SocketTimeout, func(du time.Duration) { opt.SetSocketTimeout(du) }) 104 d.wrapDurationSetter(option.MaxConnIdleTime, func(du time.Duration) { opt.SetMaxConnIdleTime(du) }) 105 d.wrapDurationSetter(option.HeartbeatInterval, func(du time.Duration) { opt.SetHeartbeatInterval(du) }) 106 d.wrapNumberSetter(option.MaxConnecting, func(nu uint64) { opt.SetMaxConnecting(option.MaxConnecting) }) 107 d.wrapNumberSetter(option.MinPoolSize, func(nu uint64) { opt.SetMinPoolSize(option.MinPoolSize) }) 108 d.wrapNumberSetter(option.MaxPoolSize, func(nu uint64) { opt.SetMaxPoolSize(option.MaxPoolSize) }) 109 110 newOpt := utils.ApplyOptions[newOption](opts...) 111 if newOpt.monitor != nil { 112 opt = opt.SetMonitor(newOpt.monitor) 113 } 114 if newOpt.poolMonitor != nil { 115 opt = opt.SetPoolMonitor(newOpt.poolMonitor) 116 } 117 118 mgoCli, err := mongo.Connect(ctx, opt) 119 if err != nil { 120 return 121 } 122 123 // authentication check 124 if err = mgoCli.Ping(ctx, nil); err != nil { 125 return 126 } 127 128 cli = &Mongo{Client: mgoCli} 129 return 130 } 131 132 func (d *defaultDialect) wrapDurationSetter(s string, setter func(du time.Duration)) { 133 if utils.IsStrBlank(s) { 134 return 135 } 136 duration, err := time.ParseDuration(s) 137 if err != nil { 138 panic(err) 139 } 140 setter(duration) 141 } 142 143 func (d *defaultDialect) wrapNumberSetter(n uint64, setter func(nu uint64)) { 144 if n > 0 { 145 setter(n) 146 } 147 } 148 149 func (d *defaultDialect) parseOption(option Option) (dsn string) { 150 return fmt.Sprintf("mongodb://%s:%s@%s/%s?authSource=%s", 151 option.User, option.Password, strings.Join(option.Endpoints, constant.Comma), option.DB, option.AuthDB) 152 }