0
# TaskSets and Task Management
1
2
TaskSets provide a way to organize related tasks and model complex user behavior patterns. Locust supports random task execution, sequential execution, and Markov chain-based probabilistic transitions between tasks.
3
4
## Capabilities
5
6
### TaskSet Base Class
7
8
The fundamental class for grouping and organizing tasks with shared state and lifecycle management.
9
10
```python { .api }
11
class TaskSet:
12
"""
13
Base class for organizing related tasks with shared state.
14
15
Attributes:
16
tasks (list | dict): Tasks to execute - functions, classes, or dict with weights
17
min_wait (float): Deprecated - minimum wait time
18
max_wait (float): Deprecated - maximum wait time
19
wait_function (callable): Function to determine wait time between tasks
20
user: Parent user instance
21
parent: Parent TaskSet or User
22
client: HTTP client from user (convenience access)
23
"""
24
25
def __init__(self, parent):
26
"""
27
Initialize TaskSet.
28
29
Args:
30
parent: Parent TaskSet or User instance
31
"""
32
33
def on_start(self):
34
"""Called when TaskSet starts executing."""
35
36
def on_stop(self):
37
"""Called when TaskSet stops executing."""
38
39
def run(self):
40
"""Main execution loop - runs tasks with wait times."""
41
42
def execute_task(self, task):
43
"""
44
Execute a single task.
45
46
Args:
47
task: Task function or class to execute
48
"""
49
50
def schedule_task(self):
51
"""Schedule the next task to be executed."""
52
53
def get_next_task(self):
54
"""
55
Get the next task to execute based on task weights.
56
57
Returns:
58
Task function or class to execute
59
"""
60
61
def wait_time(self):
62
"""
63
Calculate wait time before next task.
64
65
Returns:
66
float: Wait time in seconds
67
"""
68
69
def wait(self):
70
"""Wait before executing next task."""
71
72
def interrupt(self, reschedule=True):
73
"""
74
Interrupt current TaskSet execution.
75
76
Args:
77
reschedule (bool): Whether to reschedule the task
78
"""
79
80
@property
81
def user(self):
82
"""Get the root User instance."""
83
84
@property
85
def parent(self):
86
"""Get the parent TaskSet or User."""
87
88
@property
89
def client(self):
90
"""Get HTTP client from user (convenience property)."""
91
```
92
93
### SequentialTaskSet
94
95
TaskSet that executes tasks in the order they are defined rather than randomly selecting them.
96
97
```python { .api }
98
class SequentialTaskSet(TaskSet):
99
"""
100
TaskSet that executes tasks in sequential order.
101
102
Tasks are executed in the order they appear in the tasks list,
103
cycling back to the first task after the last one completes.
104
"""
105
106
# Inherits all TaskSet methods and attributes
107
# Overrides task selection to be sequential rather than random
108
```
109
110
### MarkovTaskSet
111
112
TaskSet that uses Markov chains for probabilistic task transitions, enabling complex user behavior modeling.
113
114
```python { .api }
115
class MarkovTaskSet(TaskSet):
116
"""
117
TaskSet using Markov chains for task transitions.
118
119
Tasks transition to other tasks based on probabilities defined
120
using @transition and @transitions decorators.
121
122
Attributes:
123
current (str): Current task/state name
124
abstract (bool): Mark as abstract class
125
"""
126
127
# Use with @transition and @transitions decorators to define state transitions
128
```
129
130
## Task Decorators
131
132
### task Decorator
133
134
Decorator to mark methods as tasks and specify their execution weight.
135
136
```python { .api }
137
def task(weight=1):
138
"""
139
Decorator to mark a method as a task.
140
141
Args:
142
weight (int): Relative weight for task selection (default: 1)
143
Higher weights make tasks more likely to be selected
144
145
Returns:
146
Decorated function marked as a task
147
148
Usage:
149
@task # weight=1
150
def simple_task(self): ...
151
152
@task(3) # weight=3 (3x more likely)
153
def important_task(self): ...
154
"""
155
```
156
157
### tag Decorator
158
159
Decorator to tag tasks for filtering during test execution.
160
161
```python { .api }
162
def tag(*tags):
163
"""
164
Decorator to tag tasks for filtering.
165
166
Args:
167
*tags (str): Variable number of tag strings
168
169
Returns:
170
Decorated function with tags
171
172
Usage:
173
@tag("api", "critical")
174
@task
175
def api_test(self): ...
176
177
@tag("slow")
178
@task
179
def slow_operation(self): ...
180
"""
181
```
182
183
## Markov Task Decorators
184
185
### transition Decorator
186
187
Decorator for defining single transitions in Markov TaskSets.
188
189
```python { .api }
190
def transition(func_name: str, weight: int = 1):
191
"""
192
Define a single transition from current task to target task.
193
194
Args:
195
func_name (str): Name of target task function
196
weight (int): Transition weight (default: 1)
197
198
Returns:
199
Decorated function with transition
200
201
Usage:
202
@transition("task_b", weight=2)
203
@task
204
def task_a(self): ...
205
"""
206
```
207
208
### transitions Decorator
209
210
Decorator for defining multiple transitions in Markov TaskSets.
211
212
```python { .api }
213
def transitions(weights):
214
"""
215
Define multiple transitions from current task to target tasks.
216
217
Args:
218
weights (dict | list): Dict of {func_name: weight} or
219
list of (func_name, weight) tuples or func_names
220
221
Returns:
222
Decorated function with transitions
223
224
Usage:
225
@transitions({"task_b": 2, "task_c": 1})
226
@task
227
def task_a(self): ...
228
229
@transitions([("task_b", 2), ("task_c", 1)])
230
@task
231
def task_a(self): ...
232
"""
233
```
234
235
## Usage Examples
236
237
### Basic TaskSet Example
238
239
```python
240
from locust import HttpUser, TaskSet, task, between
241
242
class UserBehavior(TaskSet):
243
def on_start(self):
244
# Setup for this TaskSet
245
self.login()
246
247
def login(self):
248
self.client.post("/login", json={
249
"username": "testuser",
250
"password": "secret"
251
})
252
253
@task(3)
254
def browse_pages(self):
255
pages = ["/", "/about", "/products", "/contact"]
256
page = random.choice(pages)
257
self.client.get(page)
258
259
@task(1)
260
def search(self):
261
query = random.choice(["python", "testing", "locust"])
262
self.client.get(f"/search?q={query}")
263
264
def on_stop(self):
265
# Cleanup for this TaskSet
266
self.client.post("/logout")
267
268
class WebsiteUser(HttpUser):
269
tasks = [UserBehavior]
270
wait_time = between(1, 3)
271
```
272
273
### Nested TaskSets Example
274
275
```python
276
from locust import HttpUser, TaskSet, task, between
277
278
class AdminBehavior(TaskSet):
279
weight = 1 # Less likely to be selected
280
281
@task
282
def manage_users(self):
283
self.client.get("/admin/users")
284
285
@task
286
def view_reports(self):
287
self.client.get("/admin/reports")
288
289
class ShoppingBehavior(TaskSet):
290
weight = 3 # More likely to be selected
291
292
@task(2)
293
def browse_products(self):
294
self.client.get("/products")
295
296
@task(1)
297
def add_to_cart(self):
298
product_id = random.randint(1, 100)
299
self.client.post(f"/cart/add/{product_id}")
300
301
class WebsiteUser(HttpUser):
302
tasks = [AdminBehavior, ShoppingBehavior]
303
wait_time = between(1, 5)
304
```
305
306
### SequentialTaskSet Example
307
308
```python
309
from locust import HttpUser, SequentialTaskSet, task, between
310
311
class OrderProcess(SequentialTaskSet):
312
"""Tasks execute in order: browse -> select -> checkout -> complete"""
313
314
@task
315
def browse_products(self):
316
self.client.get("/products")
317
318
@task
319
def select_product(self):
320
self.product_id = random.randint(1, 100)
321
self.client.get(f"/products/{self.product_id}")
322
323
@task
324
def add_to_cart(self):
325
self.client.post("/cart/add", json={
326
"product_id": self.product_id,
327
"quantity": 1
328
})
329
330
@task
331
def checkout(self):
332
self.client.get("/checkout")
333
self.client.post("/checkout", json={
334
"payment_method": "credit_card"
335
})
336
337
@task
338
def complete_order(self):
339
self.client.get("/order/complete")
340
# After completion, cycle back to browse_products
341
342
class ShoppingUser(HttpUser):
343
tasks = [OrderProcess]
344
wait_time = between(2, 5)
345
```
346
347
### MarkovTaskSet Example
348
349
```python
350
from locust import HttpUser, MarkovTaskSet, task, between
351
from locust.user.markov_taskset import transition, transitions
352
353
class UserJourney(MarkovTaskSet):
354
"""User behavior modeled as Markov chain with probabilistic transitions"""
355
356
@task
357
@transitions({"browse": 3, "search": 1, "logout": 1})
358
def homepage(self):
359
"""Entry point - users can browse, search, or logout"""
360
self.client.get("/")
361
362
@task
363
@transitions({"product_page": 2, "homepage": 1})
364
def browse(self):
365
"""Browse products - can go to specific product or back to homepage"""
366
self.client.get("/products")
367
368
@task
369
@transition("product_page", weight=3)
370
@transition("homepage", weight=1)
371
def search(self):
372
"""Search for products"""
373
query = random.choice(["laptop", "phone", "tablet"])
374
self.client.get(f"/search?q={query}")
375
376
@task
377
@transitions([("add_to_cart", 2), ("browse", 2), ("homepage", 1)])
378
def product_page(self):
379
"""View product details"""
380
product_id = random.randint(1, 100)
381
self.client.get(f"/products/{product_id}")
382
383
@task
384
@transitions({"checkout": 3, "browse": 1})
385
def add_to_cart(self):
386
"""Add item to cart"""
387
self.client.post("/cart/add", json={"product_id": 123})
388
389
@task
390
@transition("logout", weight=1)
391
def checkout(self):
392
"""Complete purchase"""
393
self.client.post("/checkout")
394
395
def logout(self):
396
"""End session - no @task decorator, only reached via transitions"""
397
self.client.post("/logout")
398
self.interrupt() # End this TaskSet
399
400
class MarkovUser(HttpUser):
401
tasks = [UserJourney]
402
wait_time = between(1, 3)
403
```
404
405
### TaskSet with Shared State
406
407
```python
408
from locust import HttpUser, TaskSet, task, between
409
410
class APITestSuite(TaskSet):
411
def on_start(self):
412
# Authenticate and store token
413
response = self.client.post("/auth/login", json={
414
"username": "api_user",
415
"password": "secret"
416
})
417
self.auth_token = response.json()["access_token"]
418
419
# Set headers for all subsequent requests
420
self.client.headers.update({
421
"Authorization": f"Bearer {self.auth_token}"
422
})
423
424
# Initialize shared test data
425
self.created_resources = []
426
427
@task(2)
428
def create_resource(self):
429
"""Create a new resource"""
430
resource_data = {
431
"name": f"test_resource_{random.randint(1000, 9999)}",
432
"description": "Test resource created by Locust"
433
}
434
435
response = self.client.post("/api/resources", json=resource_data)
436
if response.status_code == 201:
437
resource_id = response.json()["id"]
438
self.created_resources.append(resource_id)
439
440
@task(5)
441
def read_resource(self):
442
"""Read existing resources"""
443
if self.created_resources:
444
resource_id = random.choice(self.created_resources)
445
self.client.get(f"/api/resources/{resource_id}")
446
else:
447
# Fallback to reading first resource
448
self.client.get("/api/resources/1")
449
450
@task(1)
451
def update_resource(self):
452
"""Update an existing resource"""
453
if self.created_resources:
454
resource_id = random.choice(self.created_resources)
455
update_data = {
456
"description": f"Updated at {time.time()}"
457
}
458
self.client.put(f"/api/resources/{resource_id}", json=update_data)
459
460
@task(1)
461
def delete_resource(self):
462
"""Delete a resource"""
463
if self.created_resources:
464
resource_id = self.created_resources.pop()
465
self.client.delete(f"/api/resources/{resource_id}")
466
467
def on_stop(self):
468
# Cleanup remaining resources
469
for resource_id in self.created_resources:
470
self.client.delete(f"/api/resources/{resource_id}")
471
472
class APIUser(HttpUser):
473
tasks = [APITestSuite]
474
wait_time = between(0.5, 2)
475
```
476
477
## Types
478
479
```python { .api }
480
from typing import Union, List, Dict, Callable, Any, Optional
481
482
# Task definition types
483
TaskFunction = Callable[[], None]
484
TaskClass = type # TaskSet subclass
485
TaskWeight = int
486
TaskDict = Dict[Union[TaskFunction, TaskClass], TaskWeight]
487
TaskList = List[Union[TaskFunction, TaskClass, tuple]]
488
489
# TaskSet configuration
490
Tasks = Union[TaskList, TaskDict]
491
WaitFunction = Callable[[], float]
492
493
# Markov chain types
494
TransitionWeights = Dict[str, int]
495
TransitionList = List[Union[tuple[str, int], str]]
496
Transitions = Union[TransitionWeights, TransitionList]
497
```