# frozen_string_literal: true require "wsdirector/scenario_reader" require "wsdirector/clients_holder" require "wsdirector/results_holder" require "wsdirector/result" require "wsdirector/task" require "wsdirector/ext/deep_dup" module WSDirector def self.run(scenario, scale: 1, connection_options: {}, locals: {}, **options) scenario = ScenarioReader.parse(scenario, scale:, connection_options:, locals:) Runner.new(scenario, scale:, **options).execute end # Initiates all clients as a separate tasks (=threads) class Runner using WSDirector::Ext::DeepDup def initialize(scenario, url:, scale: 1, sync_timeout: 5, logger: nil, colorize: false) @scenario = scenario @url = url @scale = scale @logger = logger @colorize = colorize @total_count = scenario["total"] @global_holder = ClientsHolder.new(total_count, sync_timeout:) @results_holder = ResultsHolder.new end def execute Thread.abort_on_exception = true num = 0 tasks = scenario["clients"].flat_map do |client_config| name = client_config.fetch("name") result = Result.new(name) results_holder << result Array.new(client_config.fetch("multiplier")) do num += 1 id = "#{name}_#{num}" Thread.new do Task.new(client_config.deep_dup, id:, colorize:, global_holder:, result:, scale:, logger:) .run(url) end end end tasks.each(&:join) results_holder end private attr_reader :scenario, :url, :scale, :total_count, :global_holder, :results_holder, :logger, :colorize end end