SvenskaSpel / locust-plugins

A set of useful plugins/extensions for Locust
Apache License 2.0
554 stars 138 forks source link

how to stop locust when Using Locust as a library #174

Closed wohui closed 7 months ago

wohui commented 7 months ago

when i use Using Locust as a library by https://docs.locust.io/en/stable/use-as-lib.html?highlight=runner#full-example

how to stop this test my code `

start the test

runner.start(1, spawn_rate=10)

in 60 seconds stop the runner

gevent.spawn_later(60, lambda: runner.quit())

wait for the greenlets

runner.greenlet.join()

i want stop test after 30s but no effect

runner.quit() `

thank you for help

cyberw commented 7 months ago

Hi! Your question doesnt really look like it relates to locust-plugins, only locust core? Please ask questions on slack (https://communityinviter.com/apps/locustio/locust) or stackoverflow.

eldaduzman commented 7 months ago

It's very difficult to know without seeing the entire code example, but one thing that pops up to me is that you don't need a lambda expression, instead you can pass runner.quite directly.

cyberw commented 7 months ago

Damn, you're right, I didnt read it through.

@wohui you should replace gevent.spawn_later(60, lambda: runner.quit())

with gevent.spawn_later(60, runner.quit)

Hopefully that is all you need :)

cyberw commented 7 months ago

I have fixed the example now. https://github.com/locustio/locust/blob/master/examples/use_as_lib.py

wohui commented 7 months ago

I have fixed the example now. https://github.com/locustio/locust/blob/master/examples/use_as_lib.py

In this demo, where should I use "runner.quit()" to end the test Immediately?

cyberw commented 7 months ago

I dont understand your question. The example will call runner.quit after 30s.

wohui commented 7 months ago

I dont understand your question. The example will call runner.quit after 30s. gevent.spawn_later(30, runner.quit) This is the total time set. If I want to stop the test halfway while running。 I want to terminate it actively, how should I call runner.quit?

cyberw commented 7 months ago

if you want to terminate it "actively", just call runner.quit()

wohui commented 7 months ago

@cyberw sorry can use TimeScaledb when running locust as library? i dont know how to config postgres while use Environment

before this I config Postgres use os.environ do you know how to config when running locust as library

from locust import HttpUser, task, events
import os
os.environ['PGHOST'] = '192.168.0.101'
os.environ['PGUSER'] = 'postgres'
os.environ['PGPASSWORD'] = 'hui666666'
os.environ['PGDATABASE'] = 'colo_test'
class NoSlowQTaskSet(HttpUser):
    host = "http://192.168.0.101:8000"
    @task(2)
    def get_data(self):
        r = self.client.get("/get_data/test")
    @task(8)
    def say_hello(self):
        r = self.client.get("/say_hello/hui")

    def on_locust_init(self,environment, **_kwargs):
        listeners.Timescale(env=environment, testplan="timescale_listener_ex")
if __name__ == "__main__":
    run_single_user(NoSlowQTaskSet)

thank you much

cyberw commented 7 months ago

👍

You should be able to do the call listeners.Timescale(env=environment, testplan="timescale_listener_ex") directly in your lib code.

Or, if you prefer, set os.environ['LOCUST_TIMESCALE'] = "true" and import locust_plugins in your lib code, before creating your environment (this import is done automatically by main.py which is... a little weird but helpful for non lib runs)

wohui commented 7 months ago

no documentation and demo code, is a little distressing

wohui commented 7 months ago

@cyberw 'locust_plugins.listeners' has no attribute 'Timescale'

wohui commented 7 months ago

this is my full test code,can you help me? thanks so much

#!/usr/bin/env python3
import time
import locust
from locust import HttpUser, events, task
from locust.env import Environment
from locust.log import setup_logging
from locust.stats import stats_history, stats_printer
from locust_plugins import listeners
import gevent
import os
setup_logging("INFO", None)

import os
os.environ['PGHOST'] = '192.168.0.101'
os.environ['PGUSER'] = 'postgres'
os.environ['PGPASSWORD'] = 'hui666666'
os.environ['PGDATABASE'] = 'colo_test'
os.environ['LOCUST_TIMESCALE'] = "true"
class MyUser(HttpUser):
    host = "http://192.168.0.101:8000"

    @task(2)
    def get_data(self):
        r = self.client.get("/get_data/test")

    @task(8)
    def say_hello(self):
        r = self.client.get("/say_hello/hui")

    def on_locust_init(self, environment, **_kwargs):
        listeners.Timescale(env=environment, testplan="timescale_listener_ex")

    @events.test_start.add_listener
    def on_test_start(environment, **kwargs):
        print("A new test is starting")

    @events.test_stop.add_listener
    def on_test_stop(environment, **kwargs):
        print("A new test is ending")

parser = locust.argument_parser.get_parser()
# # p = parser.parse_options("--headless -f backend_test.py --host="" --timescale --pguser postgres")
p = parser._parse_optional("--headless --pghost 192.168.0.101 --timescale --override-plan-name 0227 --pguser postgres --pgpassword hui666666 --pgdatabase colo_test")

env = Environment(user_classes=[MyUser], events=events, parsed_options=p)
runner = env.create_local_runner()
listeners.Timescale(env=env, testplan="timescale_listener_ex")
# start a WebUI instance
# web_ui = env.create_web_ui("127.0.0.1", 8089)
# execute init event handlers (only really needed if you have registered any)
env.events.init.fire(environment=env, runner=runner)

# start a greenlet that periodically outputs the current stats
gevent.spawn(stats_printer(env.stats))

# start a greenlet that save current stats to history
gevent.spawn(stats_history, env.runner)

# start the test
runner.start(1, spawn_rate=10)

# in 60 seconds stop the runner
gevent.spawn_later(60, lambda: runner.quit())

# wait for the greenlets
runner.greenlet.join()

# stop the web server for good measures
# web_ui.stop()
cyberw commented 7 months ago

from locust_plugins.listeners.timescale import Timescale

cyberw commented 7 months ago

(it was moved to its own module a while back)

cyberw commented 7 months ago

no documentation and demo code, is a little distressing

You're probably the first to run this somewhat exotic combination of locust-as-a-library and Timescale, so dont expect it to be smooth.

If you need further assistance please switch to slack or stackoverflow, as I dont have any more time.

wohui commented 7 months ago

if you want to terminate it "actively", just call runner.quit()

@cyberw ,sorry for noise,I need a help, if I'm running Locust using the command line: locust --timescale --headless --host .... , is there a nice way to shut down Locust? I'm using subprocess to start or kill the process,thank you very much。

cmd = 'locust --timescale --headless --host http://192.168.0.101:8000 -u 2 -r 1 --override-plan-name 测试用户系统核心2个接口-1709542579262926900 -f "D:\py_space\colo\locust_case\locustfile_1.py" --pghost 192.168.0.101 --pgport 5432 --pguser postgres --pgpassword hui666666 --pgdatabase colo_test --run-time 3600s'
    import subprocess
    proc = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    pid = proc.pid
    time.sleep(30)
    process = psutil.Process(pid)
    process.terminate()
cyberw commented 7 months ago

Sure! You can send sigint (ctrl-c) to the process. We do that a lot in our automated tests (see test_main.py)

proc.send_signal(signal.SIGINT)
proc.communicate() # wait for it to finish