Class: CloverSandboxSimulator::ParallelExecutor
- Inherits:
-
Object
- Object
- CloverSandboxSimulator::ParallelExecutor
- Defined in:
- lib/clover_sandbox_simulator/parallel_executor.rb
Overview
Executes operations across multiple merchants in parallel
Usage:
executor = ParallelExecutor.new
# Run a block for each merchant
results = executor.run_all do |services, merchant|
charge = services.ecommerce.create_test_charge(amount: 1000)
refund = services.ecommerce.create_refund(charge_id: charge["id"])
{ charge: charge, refund: refund }
end
Instance Attribute Summary collapse
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#merchants ⇒ Object
readonly
Returns the value of attribute merchants.
-
#results ⇒ Object
readonly
Returns the value of attribute results.
Instance Method Summary collapse
-
#initialize(merchant_ids: nil) ⇒ ParallelExecutor
constructor
A new instance of ParallelExecutor.
-
#refresh_tokens_all ⇒ Hash
Refresh tokens for all merchants that have refresh tokens.
-
#run_all(max_threads: 5) {|services, merchant| ... } ⇒ Hash
Run a block for each merchant in parallel.
-
#run_card_transactions_all(transaction_count: 5, refund_percentage: 40) ⇒ Hash
Run multiple card transactions with refunds for each merchant Works without OAuth tokens (Ecommerce API only).
-
#run_day_all(multiplier: 0.5, refund_percentage: 10) ⇒ Hash
Run a full day simulation for all merchants Requires valid OAuth tokens in .env.json for Platform API.
-
#run_for(merchant_ids) {|services, merchant| ... } ⇒ Hash
Run for specific merchant IDs only.
-
#test_ecommerce_all(amount: 1000) ⇒ Hash
Run Ecommerce test (charge + refund) for all merchants.
Constructor Details
#initialize(merchant_ids: nil) ⇒ ParallelExecutor
Returns a new instance of ParallelExecutor.
21 22 23 24 25 |
# File 'lib/clover_sandbox_simulator/parallel_executor.rb', line 21 def initialize(merchant_ids: nil) @logger = CloverSandboxSimulator.logger @merchants = load_merchants(merchant_ids) @results = {} end |
Instance Attribute Details
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
19 20 21 |
# File 'lib/clover_sandbox_simulator/parallel_executor.rb', line 19 def logger @logger end |
#merchants ⇒ Object (readonly)
Returns the value of attribute merchants.
19 20 21 |
# File 'lib/clover_sandbox_simulator/parallel_executor.rb', line 19 def merchants @merchants end |
#results ⇒ Object (readonly)
Returns the value of attribute results.
19 20 21 |
# File 'lib/clover_sandbox_simulator/parallel_executor.rb', line 19 def results @results end |
Instance Method Details
#refresh_tokens_all ⇒ Hash
Refresh tokens for all merchants that have refresh tokens
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/clover_sandbox_simulator/parallel_executor.rb', line 109 def refresh_tokens_all run_all do |services, merchant| config = services.config unless config.refresh_token && !config.refresh_token.empty? next { skipped: true, reason: "No refresh token" } end unless config.oauth_enabled? next { skipped: true, reason: "OAuth not configured (need APP_ID and APP_SECRET)" } end tokens = services.oauth.refresh_current_merchant_token if tokens { refreshed: true, expires_in: tokens["expires_in"] } else { refreshed: false, error: "Refresh failed" } end end end |
#run_all(max_threads: 5) {|services, merchant| ... } ⇒ Hash
Run a block for each merchant in parallel
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/clover_sandbox_simulator/parallel_executor.rb', line 34 def run_all(max_threads: 5, &block) return {} if merchants.empty? logger.info "Running operations for #{merchants.size} merchants (max #{max_threads} threads)" pool = Concurrent::FixedThreadPool.new(max_threads) futures = {} merchants.each do |merchant| merchant_id = merchant[:id] futures[merchant_id] = Concurrent::Future.execute(executor: pool) do run_for_merchant(merchant, &block) end end # Wait for all futures to complete futures.each do |merchant_id, future| begin @results[merchant_id] = { success: true, merchant_name: merchants.find { |m| m[:id] == merchant_id }&.dig(:name), data: future.value(30) # 30 second timeout per merchant } rescue StandardError => e @results[merchant_id] = { success: false, merchant_name: merchants.find { |m| m[:id] == merchant_id }&.dig(:name), error: e. } end end pool.shutdown pool.wait_for_termination(60) print_summary @results end |
#run_card_transactions_all(transaction_count: 5, refund_percentage: 40) ⇒ Hash
Run multiple card transactions with refunds for each merchant Works without OAuth tokens (Ecommerce API only)
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/clover_sandbox_simulator/parallel_executor.rb', line 176 def run_card_transactions_all(transaction_count: 5, refund_percentage: 40) run_all(max_threads: 3) do |services, merchant| next { skipped: true, reason: "Ecommerce not configured" } unless services.ecommerce_available? results = { charges: [], refunds: [], total_charged: 0, total_refunded: 0 } # Create transactions transaction_count.times do |i| # Random amount between $5 and $75 amount = rand(500..7500) # Small delay to avoid rate limits sleep(0.5) if i > 0 charge = services.ecommerce.create_test_charge(amount: amount) next unless charge&.dig("id") results[:charges] << { id: charge["id"], amount: charge["amount"] } results[:total_charged] += charge["amount"] end # Refund some transactions refund_count = (results[:charges].size * refund_percentage / 100.0).ceil charges_to_refund = results[:charges].sample(refund_count) charges_to_refund.each_with_index do |charge, i| sleep(0.5) if i > 0 # 60% full refunds, 40% partial if rand < 0.6 refund = services.ecommerce.create_refund(charge_id: charge[:id]) else partial_amount = (charge[:amount] * rand(25..75) / 100.0).round refund = services.ecommerce.create_refund(charge_id: charge[:id], amount: partial_amount) end next unless refund&.dig("id") results[:refunds] << { id: refund["id"], charge_id: charge[:id], amount: refund["amount"] } results[:total_refunded] += refund["amount"] end results end end |
#run_day_all(multiplier: 0.5, refund_percentage: 10) ⇒ Hash
Run a full day simulation for all merchants Requires valid OAuth tokens in .env.json for Platform API
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/clover_sandbox_simulator/parallel_executor.rb', line 139 def run_day_all(multiplier: 0.5, refund_percentage: 10) run_all(max_threads: 2) do |services, merchant| config = services.config unless config.platform_enabled? next { skipped: true, reason: "OAuth token required (Platform API)" } end # Run full day simulation generator = Generators::OrderGenerator.new( services: services, refund_percentage: refund_percentage ) orders = generator.generate_realistic_day( date: Date.today, multiplier: multiplier ) stats = generator.stats { orders: orders.size, revenue: stats[:revenue], tips: stats[:tips], tax: stats[:tax], refunds: stats[:refunds] } end end |
#run_for(merchant_ids) {|services, merchant| ... } ⇒ Hash
Run for specific merchant IDs only
79 80 81 82 |
# File 'lib/clover_sandbox_simulator/parallel_executor.rb', line 79 def run_for(merchant_ids, &block) @merchants = load_merchants(merchant_ids) run_all(&block) end |
#test_ecommerce_all(amount: 1000) ⇒ Hash
Run Ecommerce test (charge + refund) for all merchants
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/clover_sandbox_simulator/parallel_executor.rb', line 88 def test_ecommerce_all(amount: 1000) run_all do |services, merchant| next { skipped: true, reason: "Ecommerce not configured" } unless services.ecommerce_available? charge = services.ecommerce.create_test_charge(amount: amount) next { error: "Charge failed" } unless charge&.dig("id") refund = services.ecommerce.create_refund(charge_id: charge["id"]) { charge_id: charge["id"], charge_amount: charge["amount"], refund_id: refund&.dig("id"), refund_amount: refund&.dig("amount") } end end |