locustio / locust

Write scalable load tests in plain Python 🚗💨
MIT License
24.51k stars 2.95k forks source link

When there are multiple users, runner.quit() cannot be used to exit. #2456

Closed KlayZhu closed 5 months ago

KlayZhu commented 10 months ago

Prerequisites

Description

When there are multiple users, runner.quit() cannot be used to exit.

When there are only one user, it can exit.

Command line

locust -f {file} -u 4 --run-time 11000s --headless --html=result.html

Locustfile contents

import time
from json import JSONDecodeError

from locust import TaskSet, between, HttpUser,task

class TestTask(TaskSet):

    @task
    def api_perf_test_1(self):
        if time.time() -self.s >=10:
            print("stop test")
            self.user.environment.runner.quit()

        url = "/"

        body = {}
        header = {}
        with self.client.get(url=url, headers=header, json=body, catch_response=True) as response:
            try:
                if response.status_code != 200:
                    response.failure("status_code !=200 ")
            except JSONDecodeError as e:
                response.failure("Response could not be decoded as JSON")
            except KeyError as e:
                response.failure("Response did not contain expected key 'resultCode'")

    def on_start(self):
        self.s =time.time()

class TestUser(HttpUser):

    host = "https://www.google.com.hk"
    wait_time = between(1, 2)
    tasks = [TestTask]

if __name__ == '__main__':
    import os

    os.system(f"locust -f {__file__} -u 1  --run-time 11000s --headless --html=result.html ")

Python version

3.8.8

Locust version

2.18.1

Operating system

win 10

KlayZhu commented 10 months ago

https://github.com/locustio/locust/issues/2449

I use the above method, comment out async_calls_to_stop.join(), and that's fine, but I don't know if it affects anything else.

cyberw commented 9 months ago

Yea, doing quit while in the User greenlet may cause issues in some cases. Perhaps quit() can try to detect if we’re in a user greenlet and launch itself in a new greenlet if it is. Worth trying at least.

petarmaric commented 8 months ago

FWIW, this is my current (albeit quite hacky) workaround:

        # HACK: Raise a *nix signal to quit on errors as the usual way of
        # `self.environment.runner.quit()` no longer works reliably when the
        # locust's 'run-time' option is used. It does quit the locust's runner,
        # but not the locust's *nix process itself - which remains alive until
        # the entire 'run-time' has expired.
        signal.raise_signal(signal.SIGTERM)
Harshan01 commented 7 months ago

If locust is running in headless mode, SIGINT would also kill the process, right? Locust anyway registers a signal handler for user interruption (Ctrl+C)

github-actions[bot] commented 5 months ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 10 days.

github-actions[bot] commented 5 months ago

This issue was closed because it has been stalled for 10 days with no activity. This does not necessarily mean that the issue is bad, but it most likely means that nobody is willing to take the time to fix it. If you have found Locust useful, then consider contributing a fix yourself!