Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to run test_start on workers. #1408

Closed
Zooce opened this issue Jun 2, 2020 · 11 comments
Closed

Ability to run test_start on workers. #1408

Zooce opened this issue Jun 2, 2020 · 11 comments

Comments

@Zooce
Copy link
Contributor

Zooce commented Jun 2, 2020

Is your feature request related to a problem? Please describe.

I have a load test where some setup is needed, but I really only need to do it once to set some global variables, that all spawned users to use.

Previously this was done with the HttpLocust.setup method. Unfortunately, now there is the test_start functionality which only runs on the master.

Describe the solution you'd like

Allow the test_start functionality to run on workers.

Describe alternatives you've considered

I can use the HttpUser.on_start method, but it results in ever single user that is spawned making a request (part of the work that I have to do in the setup), and it's not ideal.

@Zooce
Copy link
Contributor Author

Zooce commented Jun 2, 2020

I seem to have found a workaround for this -- bypassing the logic in HttpUser.on_start if the global variables I'm trying to set have already been set by another spawned user.

class MyUser(HttpUser):
    def on_start(self):
        global SOME_GLOBAL
        if not SOME_GLOBAL:
            # do the setup work

@cyberw
Copy link
Collaborator

cyberw commented Jun 3, 2020

The setup method was removed because it was running in a bit of a strange place - people ended up getting confused because it was only being run on the first user, so if you set an instance property it would only be available on the FIRST instance of the User. Sometimes it was also run before the instance was even constructed (when there was no .client or anything). Maybe we should reintroduce it in some form.

Another way to work around it is like this:

class MyUser(User):
    _first_instance = True

    def __init__(self, parent):
        super().__init__(parent)
        if MyUser._first_instance:
            MyUser._first_instance = False
            # do the setup work

Tbh, I'm not sure what the difference between on_start and __init__ really is, since on_start is called immediately after construction. We do catch any InterruptTaskSet thrown in on_start, but I dont really see any use case for throwing that there anyway..

@cyberw
Copy link
Collaborator

cyberw commented Jun 3, 2020

Also, if what you want it just to do some general one-off initialization (not in the context of a User), you can do it using the init event, which IS triggered on all locust processes:

from locust import events
from locust.runners import MasterRunner
...
@events.init.add_listener
def on_locust_init(environment, **kwargs):
    if not isinstance(environment.runner, MasterRunner):
        # do the setup work

@heyman
Copy link
Member

heyman commented Jun 4, 2020

We could consider adding an additional event that is triggered on the worker nodes when they start spawning users. We would have to consider if it should trigger for new worker nodes that connects while a test is running (I guess it should?). Though I'm not sure it's necessary, since there are work-arounds like the one by @Zooce above.

The setup method was removed for a good reason, and I don't think it makes sense to re-add it.

@Zooce
Copy link
Contributor Author

Zooce commented Jun 5, 2020

Removing the setup method was probably a good idea, I agree.

@cyberw -- I didn't realize there was an init even listener I could add. That's essentially what I'm looking for. I just looked at the documentation and found https://docs.locust.io/en/stable/extending-locust.html -- however, from that description/use case it wasn't clear to me that it's fired before everything else (and for every process). Note that I'm very new to locust and not a web developer.

Maybe a simple documentation update is all that is needed?

@cyberw
Copy link
Collaborator

cyberw commented Jun 5, 2020

Removing the setup method was probably a good idea, I agree.

@cyberw -- I didn't realize there was an init even listener I could add. That's essentially what I'm looking for. I just looked at the documentation and found https://docs.locust.io/en/stable/extending-locust.html -- however, from that description/use case it wasn't clear to me that it's fired before everything else (and for every process). Note that I'm very new to locust and not a web developer.

Maybe a simple documentation update is all that is needed?

I think you are right, the documentation is not clear and doesnt indicate that the init event is very useful for other things than adding web routes. Could I bother you to write something and make a PR?

@Zooce
Copy link
Contributor Author

Zooce commented Jun 6, 2020

Certainly! I'm going to use that code you showed a couple of comments ago (if that's okay with you) since I immediately understood the usage after reading it -- it's a good example of how to use the init event.

I'll have the PR up soon.

@robbrit
Copy link

robbrit commented Sep 23, 2020

Is there a way to access the HTTP client from a listener? I want to be able to make a few HTTP requests to the target during the test_start event, but since that's not within the User context I can't do it.

The global flag setup works fine for single-node setup but that's not ideal long term if we want to scale up.

To elaborate on the use-case: I'm stress testing an API and before hammering it, I request a JWT from the auth server. I can hard-code a JWT into the Locust test, but that's a bit brittle if the JWT secret or the contents ever change.

@cyberw
Copy link
Collaborator

cyberw commented Sep 24, 2020

Is there a way to access the HTTP client from a listener? I want to be able to make a few HTTP requests to the target during the test_start event, but since that's not within the User context I can't do it.

In short, no, not from the test_start/stop events. But there is nothing stopping you from making an HTTP request ”manually”, using requests directly. It just wont be logged.

@kamalk-groww
Copy link

@cyberw If I use requests inside test_start and then spawn multiple workers then I get the following error and load test never starts

objc[9322]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called.
objc[9323]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called.
objc[9322]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
objc[9323]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
[2024-03-16 22:13:10,686] GM-C02FM31JMD6M/INFO/locust.runners: Spawning is complete and report waittime is expired, but not all reports received from workers: {"LoadTest": 0} (0 total users)
[2024-03-16 22:13:13,710] GM-C02FM31JMD6M/INFO/locust.runners: Worker GM-C02FM31JMD6M_f8b0d490d5204fd5bb73e49e82f57ecb failed to send heartbeat, setting state to missing.
[2024-03-16 22:13:13,710] GM-C02FM31JMD6M/INFO/locust.runners: Worker GM-C02FM31JMD6M_7b327b6b1ba34651add3e0b12d75bb56 failed to send heartbeat, setting state to missing.
[2024-03-16 22:13:13,710] GM-C02FM31JMD6M/INFO/locust.runners: The last worker went missing, stopping test.

@cyberw
Copy link
Collaborator

cyberw commented Mar 16, 2024

Interesting. Can you share the full locustfile? In a separate ticket, because your issue doesnt really relate to the original issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants