Is there a way to keep and manage an parallel/asyncronous task queue?

I’m playing around with writing a simple load tester (sort of like locust). I want to maintain a task-queue/pool of workers making requests to my web app.

When the program starts, the worker pool will fill up. As some requests finish, more requests are added until the user stops it.

I’ve looked through the documentation for base/parallel and read a bit about Tasks, @async, and Channels, but it seems like they mostly have to do with definite loops rather than indefinite loops.

Can you suggest a different way to go about doing this or another library I should try?

Thanks in advance!

Welcome! Sounds a lot of what @tisztamo does with lightweight actors:

or maybe also

Tasks in Julia can start other tasks (with @async or @spawn). They are lightweight. You can give arguments to their functions or send them messages via channels. Thus there is no practical limitation for iterations they can do.

2 Likes

If I understand correctly, your plan is to create a central scheduler that selects the next action for every idle “user” and dispatches the work of sending out requests (running the function that is called a @task in Locust.) to the worker pool. Is that correct?

This seems possible with Julia tasks, e.g. a very simple implementation could be that you create a single channel which is filled by the scheduler with Locust-like @tasks, and all the (idle) workers (Julia tasks) are reading from it at the other end. After reading the Locust-like @task descriptor, the worker runs it, notifies the scheduler using another channel, and goes back to reading. The scheduler then selects a new Locust @task for that user. The number of workers can be much higher than the number of threads, and the Julia task scheduler will do the work of distributing the load between the tasks, so this should work and use more or less all the resources of a single machine. But the central scheduler can become a bottleneck, especially when you later want to move to distributed processing.

Another possibility is to model every user with its own Julia task, or even use an actor model, where every user is an actor. This will get you better scalability and possibly nicer code. E.g. Circo promises to auto-balance actors between distributed nodes during runtime, but it is not yet really usable and documented. For quick results I would suggest trying out Actors.jl.

Note that I am looking for a use case to create a sample showing how to use Circo in real life (sort of a reference application), and I find this one a real fit. Please PM me if you are interested in working together!

2 Likes