@@ -35,6 +35,105 @@ var (
3535 trackUserLatency bool
3636)
3737
38+ // ResolvedSettings holds the final resolved settings after applying precedence
39+ type ResolvedSettings struct {
40+ Workers int
41+ TPS float64
42+ StatsInterval time.Duration
43+ BufferSize int
44+ DryRun bool
45+ Debug bool
46+ TrackReceipts bool
47+ TrackBlocks bool
48+ TrackUserLatency bool
49+ Prewarm bool
50+ }
51+
52+ // resolveSettings applies precedence: CLI > Config > Default
53+ func resolveSettings (cfg * config.LoadConfig , cmd * cobra.Command ) ResolvedSettings {
54+ settings := ResolvedSettings {
55+ // Default values
56+ Workers : 1 ,
57+ TPS : 0 ,
58+ StatsInterval : 10 * time .Second ,
59+ BufferSize : 1000 ,
60+ DryRun : false ,
61+ Debug : false ,
62+ TrackReceipts : false ,
63+ TrackBlocks : false ,
64+ TrackUserLatency : false ,
65+ Prewarm : false ,
66+ }
67+
68+ // Apply config values if present
69+ if cfg .Settings != nil {
70+ if cfg .Settings .Workers != nil {
71+ settings .Workers = * cfg .Settings .Workers
72+ }
73+ if cfg .Settings .TPS != nil {
74+ settings .TPS = * cfg .Settings .TPS
75+ }
76+ if cfg .Settings .StatsInterval != nil {
77+ settings .StatsInterval = * cfg .Settings .StatsInterval
78+ }
79+ if cfg .Settings .BufferSize != nil {
80+ settings .BufferSize = * cfg .Settings .BufferSize
81+ }
82+ if cfg .Settings .DryRun != nil {
83+ settings .DryRun = * cfg .Settings .DryRun
84+ }
85+ if cfg .Settings .Debug != nil {
86+ settings .Debug = * cfg .Settings .Debug
87+ }
88+ if cfg .Settings .TrackReceipts != nil {
89+ settings .TrackReceipts = * cfg .Settings .TrackReceipts
90+ }
91+ if cfg .Settings .TrackBlocks != nil {
92+ settings .TrackBlocks = * cfg .Settings .TrackBlocks
93+ }
94+ if cfg .Settings .TrackUserLatency != nil {
95+ settings .TrackUserLatency = * cfg .Settings .TrackUserLatency
96+ }
97+ if cfg .Settings .Prewarm != nil {
98+ settings .Prewarm = * cfg .Settings .Prewarm
99+ }
100+ }
101+
102+ // Apply CLI values if explicitly set (CLI wins over config)
103+ if cmd .Flags ().Changed ("workers" ) {
104+ settings .Workers = workers
105+ }
106+ if cmd .Flags ().Changed ("tps" ) {
107+ settings .TPS = tps
108+ }
109+ if cmd .Flags ().Changed ("stats-interval" ) {
110+ settings .StatsInterval = statsInterval
111+ }
112+ if cmd .Flags ().Changed ("buffer-size" ) {
113+ settings .BufferSize = bufferSize
114+ }
115+ if cmd .Flags ().Changed ("dry-run" ) {
116+ settings .DryRun = dryRun
117+ }
118+ if cmd .Flags ().Changed ("debug" ) {
119+ settings .Debug = debug
120+ }
121+ if cmd .Flags ().Changed ("track-receipts" ) {
122+ settings .TrackReceipts = trackReceipts
123+ }
124+ if cmd .Flags ().Changed ("track-blocks" ) {
125+ settings .TrackBlocks = trackBlocks
126+ }
127+ if cmd .Flags ().Changed ("track-user-latency" ) {
128+ settings .TrackUserLatency = trackUserLatency
129+ }
130+ if cmd .Flags ().Changed ("prewarm" ) {
131+ settings .Prewarm = prewarm
132+ }
133+
134+ return settings
135+ }
136+
38137var rootCmd = & cobra.Command {
39138 Use : "seiload" ,
40139 Short : "Sei Chain Load Test v2" ,
@@ -88,42 +187,45 @@ func runLoadTest(ctx context.Context, cmd *cobra.Command, args []string) error {
88187 return fmt .Errorf ("failed to load config: %w" , err )
89188 }
90189
190+ // Resolve settings with precedence: CLI > Config > Default
191+ settings := resolveSettings (cfg , cmd )
192+
91193 log .Printf ("🚀 Starting Sei Chain Load Test v2" )
92194 log .Printf ("📁 Config file: %s" , configFile )
93195 log .Printf ("🎯 Endpoints: %d" , len (cfg .Endpoints ))
94- log .Printf ("👥 Workers per endpoint: %d" , workers )
95- log .Printf ("🔧 Total workers: %d" , len (cfg .Endpoints )* workers )
196+ log .Printf ("👥 Workers per endpoint: %d" , settings . Workers )
197+ log .Printf ("🔧 Total workers: %d" , len (cfg .Endpoints )* settings . Workers )
96198 log .Printf ("📊 Scenarios: %d" , len (cfg .Scenarios ))
97- log .Printf ("⏱️ Stats interval: %v" , statsInterval )
98- log .Printf ("📦 Buffer size per worker: %d" , bufferSize )
99- if tps > 0 {
100- log .Printf ("📈 Transactions per second: %.2f" , tps )
199+ log .Printf ("⏱️ Stats interval: %v" , settings . StatsInterval )
200+ log .Printf ("📦 Buffer size per worker: %d" , settings . BufferSize )
201+ if settings . TPS > 0 {
202+ log .Printf ("📈 Transactions per second: %.2f" , settings . TPS )
101203 }
102- if dryRun {
204+ if settings . DryRun {
103205 log .Printf ("📝 Dry run: enabled" )
104206 }
105- if trackReceipts {
207+ if settings . TrackReceipts {
106208 log .Printf ("📝 Track receipts: enabled" )
107209 }
108- if trackBlocks {
210+ if settings . TrackBlocks {
109211 log .Printf ("📝 Track blocks: enabled" )
110212 }
111- if prewarm {
213+ if settings . Prewarm {
112214 log .Printf ("📝 Prewarm: enabled" )
113215 }
114- if trackUserLatency {
216+ if settings . TrackUserLatency {
115217 log .Printf ("📝 Track user latency: enabled" )
116218 }
117219 log .Println ()
118220
119221 // Enable mock deployment in dry-run mode
120- if dryRun {
222+ if settings . DryRun {
121223 cfg .MockDeploy = true
122224 }
123225
124226 // Create statistics collector and logger
125227 collector := stats .NewCollector ()
126- logger := stats .NewLogger (collector , statsInterval , debug )
228+ logger := stats .NewLogger (collector , settings . StatsInterval , settings . Debug )
127229
128230 err = service .Run (ctx , func (ctx context.Context , s service.Scope ) error {
129231 // Create the generator from the config struct
@@ -133,14 +235,14 @@ func runLoadTest(ctx context.Context, cmd *cobra.Command, args []string) error {
133235 }
134236
135237 // Create the sender from the config struct
136- snd , err := sender .NewShardedSender (cfg , bufferSize , workers )
238+ snd , err := sender .NewShardedSender (cfg , settings . BufferSize , settings . Workers )
137239 if err != nil {
138240 return fmt .Errorf ("failed to create sender: %w" , err )
139241 }
140242
141243 // Create and start block collector if endpoints are available
142244 var blockCollector * stats.BlockCollector
143- if len (cfg .Endpoints ) > 0 && trackBlocks {
245+ if len (cfg .Endpoints ) > 0 && settings . TrackBlocks {
144246 blockCollector = stats .NewBlockCollector ()
145247 collector .SetBlockCollector (blockCollector )
146248 s .SpawnBgNamed ("block collector" , func () error {
@@ -149,24 +251,24 @@ func runLoadTest(ctx context.Context, cmd *cobra.Command, args []string) error {
149251 }
150252
151253 // Create and start user latency tracker if endpoints are available
152- if len (cfg .Endpoints ) > 0 && trackUserLatency {
153- userLatencyTracker := stats .NewUserLatencyTracker (statsInterval )
254+ if len (cfg .Endpoints ) > 0 && settings . TrackUserLatency {
255+ userLatencyTracker := stats .NewUserLatencyTracker (settings . StatsInterval )
154256 s .SpawnBgNamed ("user latency tracker" , func () error {
155257 return userLatencyTracker .Run (ctx , cfg .Endpoints [0 ])
156258 })
157259 }
158260
159261 // Enable dry-run mode in sender if specified
160- if dryRun {
262+ if settings . DryRun {
161263 snd .SetDryRun (true )
162264 }
163- if debug {
265+ if settings . Debug {
164266 snd .SetDebug (true )
165267 }
166- if trackReceipts {
268+ if settings . TrackReceipts {
167269 snd .SetTrackReceipts (true )
168270 }
169- if trackBlocks {
271+ if settings . TrackBlocks {
170272 snd .SetTrackBlocks (true )
171273 }
172274
@@ -175,17 +277,17 @@ func runLoadTest(ctx context.Context, cmd *cobra.Command, args []string) error {
175277
176278 // Create dispatcher
177279 dispatcher := sender .NewDispatcher (gen , snd )
178- if tps > 0 {
280+ if settings . TPS > 0 {
179281 // Convert TPS to interval: 1/tps seconds = (1/tps) * 1e9 nanoseconds
180- intervalNs := int64 ((1.0 / tps ) * 1e9 )
282+ intervalNs := int64 ((1.0 / settings . TPS ) * 1e9 )
181283 dispatcher .SetRateLimit (time .Duration (intervalNs ))
182284 }
183285
184286 // Set statistics collector for dispatcher
185287 dispatcher .SetStatsCollector (collector )
186288
187289 // Set up prewarming if enabled
188- if prewarm {
290+ if settings . Prewarm {
189291 log .Printf ("🔥 Creating prewarm generator..." )
190292 prewarmGen := generator .NewPrewarmGenerator (cfg , gen )
191293 dispatcher .SetPrewarmGenerator (prewarmGen )
@@ -198,7 +300,7 @@ func runLoadTest(ctx context.Context, cmd *cobra.Command, args []string) error {
198300 log .Printf ("✅ Connected to %d endpoints" , snd .GetNumShards ())
199301
200302 // Perform prewarming if enabled (before starting logger to avoid logging prewarm transactions)
201- if prewarm {
303+ if settings . Prewarm {
202304 if err := dispatcher .Prewarm (ctx ); err != nil {
203305 return fmt .Errorf ("failed to prewarm accounts: %w" , err )
204306 }
@@ -216,20 +318,20 @@ func runLoadTest(ctx context.Context, cmd *cobra.Command, args []string) error {
216318 sigChan := make (chan os.Signal , 1 )
217319 signal .Notify (sigChan , syscall .SIGINT , syscall .SIGTERM )
218320
219- log .Printf ("📈 Logging statistics every %v (Press Ctrl+C to stop)" , statsInterval )
220- if dryRun {
321+ log .Printf ("📈 Logging statistics every %v (Press Ctrl+C to stop)" , settings . StatsInterval )
322+ if settings . DryRun {
221323 log .Printf ("📝 Dry-run mode: Simulating requests without sending" )
222324 }
223- if debug {
325+ if settings . Debug {
224326 log .Printf ("🐛 Debug mode: Each transaction will be logged" )
225327 }
226- if trackReceipts {
328+ if settings . TrackReceipts {
227329 log .Printf ("📝 Track receipts mode: Receipts will be tracked" )
228330 }
229- if trackBlocks {
331+ if settings . TrackBlocks {
230332 log .Printf ("📝 Track blocks mode: Block data will be collected" )
231333 }
232- if trackUserLatency {
334+ if settings . TrackUserLatency {
233335 log .Printf ("📝 Track user latency mode: User latency will be tracked" )
234336 }
235337 log .Print (strings .Repeat ("=" , 60 ))
0 commit comments