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

"Sticky" user types on workers #2522

Closed
2 of 6 tasks
mgor opened this issue Dec 27, 2023 · 4 comments
Closed
2 of 6 tasks

"Sticky" user types on workers #2522

mgor opened this issue Dec 27, 2023 · 4 comments

Comments

@mgor
Copy link
Contributor

mgor commented Dec 27, 2023

Prerequisites

Description

I'm working on a feature where it would be possible to "stick" a certain user type to a (set of) workers.

The use case being a user type I have that depends on some native libraries, and said libraries have problem if with in the same process one want to run two different contexts (username + certificate).

The tought is to be able to "tag" a user type, e.g.

class User(metaclass=UserMeta):
  ...
  sticky_tag: Optional[str] = None
  ...

This would then be used in UsersDispatcher::_add_users_on_workers:

        for user in self._user_generator:
            if not user:
                self._no_user_to_spawn = True
                break
            sticky_tag = self._sticky_users_map.get(user, None)
            worker_node = next(self._worker_node_generator)

            if sticky_tag is not None:
                sticky_worker_id = self._sticky_workers_map.get(sticky_tag, None)
                if sticky_worker_id is None:
                    sticky_worker_id = worker_node.id
                    self._sticky_workers_map.update({sticky_tag: sticky_worker_id})
                else:
                    while worker_node.id != sticky_worker_id:
                        worker_node = next(self._worker_node_generator)
            elif len(self._sticky_workers_map) > 0:  # @TODO: do we need this?
                sticky_worker_ids = self._sticky_workers_map.values()
                while worker_node.id in sticky_worker_ids:
                    worker_node = next(self._worker_node_generator)
            # else: works as before

This is right now only a thought experiment, but I wanted feedback whether this was something that would be accepted by the community.

Also, outstanding issues:

  • how does the while-loop affect balacing of users
  • how to spread a user type over more than one worker
  • should a non-sticky user type be "allowed" on a worker that has sticky user types
  • ...

I know the dispatcher code is... kind of sacred? ;)

@cyberw
Copy link
Collaborator

cyberw commented Dec 27, 2023

The dispatcher code is not "sacred", but it was contributed by @mboutet and I dont know if he's still around? (so I'm hesitant to change it)

While the dispatcher implementation does seem to hold up for most use cases it is "less deterministic" than the old one and doesnt scale as well with high user, worker and user type counts.

What would be kind of cool is offering a completely separate algorithm: Not based on specifying weights and a total user count but on per-User type-numbers (like most other load test tools do it). This might involve a little more work than what you had imagined, but that would make me like the proposed change more :)

@mgor
Copy link
Contributor Author

mgor commented Dec 27, 2023

Yeah, bad choice of word, "sacred", but I remembered about reading in some thread (or if it was in code?) that changes to it wasn't advised :)

Well, I have a couple of days now when the rest of the team has vacation that I could spend looking into it.

You are referring to "the old one", has there been a different dispatcher implementation?
I could look through the git history if that is the case.

I'll start working on a DeterministicUsersDispatcher then, instead of patching the current algorithm. Basically, not using weights, only fixed numbers and also being able to "tag" user types to a set of workers.

@cyberw
Copy link
Collaborator

cyberw commented Dec 27, 2023

The old one was completely different (locust 1.x), done on the workers not on the master (which had other limitations, because each worker had exactly the same distribution), so it is not much to look at :)

Cool! The current implementation is still pretty deterministic (so you should probably name the new one something else), it is just that it has time ticks as opposed to the old one, which had no time ticks (if I remember correctly). Probably dont want to change that in your PR, as that would be a major change :)

Perhaps it could be named CountBasedUserDispatcher? (as opposed to the current one which is "weight based")

To be able to use it fully there would need to be some ui/command line changes too (because you would specify counts for each user type instead of just a total user count), but if you build the dispatcher implementation I can help out with the other stuff.

@mgor
Copy link
Contributor Author

mgor commented Jan 8, 2024

I have something working, but I want to run some extensive testing in our project before creating a PR here for it.

@mgor mgor closed this as completed Feb 20, 2024
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

2 participants