예제 #1
0
    def run(self, timeout=None):
        '''
        Run the load test. Optionally a timeout can be set to limit the run time
        of the load test
        '''
        if timeout:
            try:
                timeout = parse_timespan(timeout)
            except ValueError:
                logger.error(
                    "Valid --run-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc."
                )
                sys.exit(1)
            self.timeout = timeout
            logger.info("Run time limit set to %s seconds" % timeout)

            def timelimit_stop():
                logger.info("Time limit reached. Stopping Locust.")
                logger.info(json.dumps(self.stats()))
                logger.info("Run time limit reached: {0} seconds".format(
                    self.timeout))
                runners.locust_runner.quit()

            gevent.spawn_later(timeout, timelimit_stop)
        try:
            logger.info("Starting Locust with settings {0}".format(
                vars(self.settings)))
            runners.locust_runner = runners.LocalLocustRunner(
                self.settings.classes, self.settings)
            runners.locust_runner.start_hatching(wait=True)
            self.start_time = time.time()
            runners.locust_runner.greenlet.join()
            self.end_time = time.time()
            logger.info('Locust completed {0} requests with {1} errors'.format(
                runners.locust_runner.stats.num_requests,
                len(runners.locust_runner.errors)))

        except Exception as e:
            logger.error("Locust exception {0}".format(repr(e)))

        finally:
            events.quitting.fire()
예제 #2
0
파일: web.py 프로젝트: aherod20/locust
def swarm():
    assert request.method == "POST"

    locust_count = int(request.form["locust_count"])
    hatch_rate = float(request.form["hatch_rate"])
    #Check that option runtime is running

    runtime = str(request.form["runtime"])
    if runtime is not None:
        try:
            boptions.run_time = parse_timespan(runtime)
        except ValueError:
            logger.error(
                "Valid --run-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc."
            )
            sys.exit(1)

        runtime = boptions.run_time
    if runtime is not None:
        gevent.spawn_later(boptions.run_time, main.timelimit_stop)
    runners.locust_runner.start_hatching(locust_count, hatch_rate)

    return jsonify({'success': True, 'message': 'Swarming started'})
예제 #3
0
 def test_parse_timespan(self):
     self.assertEqual(7, parse_timespan("7"))
     self.assertEqual(7, parse_timespan("7s"))
     self.assertEqual(60, parse_timespan("1m"))
     self.assertEqual(7200, parse_timespan("2h"))
     self.assertEqual(3787, parse_timespan("1h3m7s"))
예제 #4
0
class Producer(TaskQueueLocust):
  """
  Virtual TaskQueue user producing tasks
  """

  # Locustio has CLI --run-time parameter which limits execution time,
  # but it kills locusts without giving them to report latest
  # action to validation log.
  stop_timeout = parse_timespan(os.environ['RUN_TIME'])

  class ProducerTasks(locust.TaskSet):
    """
    Set of actions (locust tasks) performed by producer
    """

    @locust.task
    def add_tasks(self):
      """ The only action performed by producer.
      Sends BulkAdd request to TaskQueue protobuffer API.
      Every added task is reported to validation log.
      """
      bulk_add = taskqueue_service_pb2.TaskQueueBulkAddRequest()
      tasks = {}
      for _ in range(BULK_SIZES):
        add_task = bulk_add.add_request.add()
        add_task.app_id = bytes(TEST_PROJECT, 'utf8')
        add_task.queue_name = bytes(PULL_QUEUE, 'utf8')
        add_task.mode = taskqueue_service_pb2.TaskQueueMode.PULL
        add_task.task_name = bytes(str(uuid.uuid4()), 'utf8')
        work_times = self.generate_work_times()
        add_task.body = bytes(work_times, 'utf8') + b':' + next(BIG_PAYLOADS)
        add_task.eta_usec = 0
        tasks[add_task.task_name] = work_times

      # Send request to TaskQueue
      with self.client.protobuf('BulkAdd', bulk_add) as response:
        # Report what tasks were added
        for task in response.taskresult:
          if task.result == taskqueue_service_pb2.TaskQueueServiceError.OK:
            self.locust.log_action(
              'ADDED', str(task.chosen_task_name, 'utf8'),
              tasks[task.chosen_task_name]
            )
          else:
            self.locust.log_action(task.result, '?', '?')

    @staticmethod
    def generate_work_times():
      """ Generates a string representing execution scenario for a task.
      The string is space-separated list of numbers.
      Every number corresponds to task processing attempt and tells
      worker how long should take execution of a task.
      """
      simulate_failures = next(FAIL_SEQUENCE)
      work_time_seq = (str(next(WORK_TIME))
                       for _ in range(simulate_failures + 1))
      return ' '.join(work_time_seq)

  task_set = ProducerTasks
  min_wait = 800
  max_wait = 1200
예제 #5
0
 def test_parse_timespan(self):
     self.assertEqual(7, parse_timespan("7"))
     self.assertEqual(7, parse_timespan("7s"))
     self.assertEqual(60, parse_timespan("1m"))
     self.assertEqual(7200, parse_timespan("2h"))
     self.assertEqual(3787, parse_timespan("1h3m7s"))
예제 #6
0
파일: plugin.py 프로젝트: yannlv/tancust
    def start_test(self):

        # install SIGTERM handler
        def sig_term_handler():
            logger.info("##### Locust plugin: Got SIGTERM signal")
            self.shutdown(0)
            gevent.signal(signal.SIGTERM, sig_term_handler)

        def spawn_local_slaves(count):
            """
            Spawn *local* locust slaves : data aggregation will NOT work with *remote* slaves
            """
            try:
                args = ['locust']
                args.append('--locustfile={}'.format(str(self.locustfile)))
                args.append('--slave')
                args.append('--master-host={}'.format(self.master_host))
                args.append('--master-port={}'.format(self.master_port))
                args.append('--resplogfile={}'.format(self.locustlog_file))
                logger.info("##### Locust plugin: slave args = {}".format(args))

                # Spawning the slaves in shell processes (security warning with the use of 'shell=True')
                self._locustslaves = [subprocess.Popen(' '.join(args), shell=True, stdin=None,
                            stdout=open('{}/locust-slave-{}.log'.format(self.core.artifacts_dir, i), 'w'),
                            stderr=subprocess.STDOUT) for i in range(count)]
                #slaves = [SlaveLocustRunner(self._locustclasses, self._options) for _ in range(count)] # <-- WRONG: This will spawn slave running on the same CPU core as master
                time.sleep(1)

                logger.info("##### Locust plugin: Started {} new locust slave(s)".format(len(self._locustslaves)))
                logger.info("##### Locust plugin: locust slave(s) PID = {}".format(self._locustslaves))
            except socket.error as e:
                logger.error("##### Locust plugin: Failed to connect to the Locust master: %s", e)
                sys.exit(-1)
            except Exception as e:
                logger.error("##### Locust plugin: Failed to spawn locust slaves: %s", e)
                sys.exit(-1)

        try:
            logger.info("##### Locust plugin: Starting Locust %s" % version)

            # run the locust 

            ### FIXME
            #if self.csvfilebase:
            #    gevent.spawn(stats_writer, self.csvfilebase)
            ### /FIXME

            if self.run_time:
                if not self.no_web:
                    logger.error("##### Locust plugin: The --run-time argument can only be used together with --no-web")
                    sys.exit(1)
                try:
                    self.run_time = parse_timespan(self.run_time)
                except ValueError:
                    logger.error("##### Locust plugin: Valid --time-limit formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.")
                    sys.exit(1)
                def spawn_run_time_limit_greenlet():
                    logger.info("##### Locust plugin: Run time limit set to %s seconds" % self.run_time)
                    def timelimit_stop():
                        logger.info("##### Locust plugin: Time limit reached. Stopping Locust.")
                        self._locustrunner.quit()
                        logger.debug("######## DEBUG: timelimit_stop()/self._locustrunner.quit() passed")
                    def on_greenlet_completion():
                        logger.debug("######## DEBUG: Locust plugin: on_greenlet_completion()")

                    #gevent.spawn_later(self.run_time, timelimit_stop)
                    gl = gevent.spawn_later(self.run_time, timelimit_stop)
                    # linking timelimit greenlet to main greenlet and get a feedback of its execution
                    #gl.link(on_greenlet_completion)



            # locust runner : web monitor
            if not self.no_web and not self.slave and self._locustrunner is None:
                # spawn web greenlet
                logger.info("##### Locust plugin: Starting web monitor at %s:%s" % (self.web_host or "*", self.port))
                main_greenlet = gevent.spawn(web.start, self._locustclasses, self._options)


            # locust runner : standalone
            if not self.master and not self.slave and self._locustrunner is None:
                logger.info("##### Locust plugin: LocalLocustRunner about to be launched")
                self._locustrunner = LocalLocustRunner(self._locustclasses, self._options)
                # spawn client spawning/hatching greenlet
                if self.no_web:
                    logger.info("##### Locust plugin: LocalLocustRunner.start_hatching()")
                    self._locustrunner.start_hatching(wait=True)
                    main_greenlet = self._locustrunner.greenlet
                if self.run_time:
                    logger.info("##### Locust plugin: spawn_run_time_limit_greenlet()")
                    spawn_run_time_limit_greenlet()
                    logger.info("##### Locust plugin: spawn_run_time_limit_greenlet() passed")

            # locust runner : master/slave mode (master here)
            elif self.master and self._locustrunner is None:
                self._locustrunner = MasterLocustRunner(self._locustclasses, self._options)
                logger.info("##### Locust plugin: MasterLocustRunner started")
                time.sleep(1)
                if self.no_web:
                    gevent.spawn(spawn_local_slaves(self.expect_slaves))
                    while len(self._locustrunner.clients.ready) < self.expect_slaves:
                        logger.info("##### Locust plugin: Waiting for slaves to be ready, %s of %s connected",
                                     len(self._locustrunner.clients.ready), self.expect_slaves)
                        time.sleep(1)
                    self._locustrunner.start_hatching(self.num_clients, self.hatch_rate)
                    logger.debug("######## DEBUG: MasterLocustRunner/start_hatching()")
                    main_greenlet = self._locustrunner.greenlet
                if self.run_time:
                    try:
                        spawn_run_time_limit_greenlet()
                    except Exception as e:
                        logger.error("##### Locust plugin: exception raised in spawn_run_time_limit_greenlet() = {}".format(e))

            # locust runner : master/slave mode (slave here)
            #elif self.slave and self._locustrunner is None:
            #    if self.run_time:
            #        logger.error("##### Locust plugin: --run-time should be specified on the master node, and not on slave nodes")
            #        sys.exit(1)
            #    try:
            #        self._locustrunner = SlaveLocustRunner(self._locustclasses, self._options)
            #        main_greenlet = self._locustrunner.greenlet
            #    except socket.error as e:
            #        logger.error("##### Locust plugin: Failed to connect to the Locust master: %s", e)
            #        sys.exit(-1)
            return self._locustrunner

            self._locustrunner.greenlet.join()
            code = 0
            if len(self._locustrunner.errors):
                code = 1
                self.shutdown(code=code)
        except KeyboardInterrupt as e:
            self.shutdown(0)