Chapter 7 · TaskSet and Nested Tasks
Chapter goals: Master the TaskSet class for hierarchical task organization, learn to use
interrupt()to exit sub-task sets, and understandon_start/on_stoplifecycle methods.
7.1 Why TaskSet Exists
When user behavior models grow complex (e.g., "login → browse products → add to cart → checkout"), stacking all @task methods in one HttpUser class becomes unmaintainable. TaskSet lets you group tasks by business scenario:
from locust import HttpUser, TaskSet, task, between
class BrowsingBehavior(TaskSet):
"""Simulate a user browsing products"""
@task(5)
def view_products(self):
self.client.get("/api/products")
@task(3)
def view_product_detail(self):
self.client.get("/api/products/1")
@task(1)
def stop_browsing(self):
# Exit browsing mode
self.interrupt()
class ShoppingUser(HttpUser):
wait_time = between(1, 3)
host = "https://shop.example.com"
tasks = {BrowsingBehavior: 10} # Weight 10HttpUser references one or more TaskSet classes via the tasks attribute. When a TaskSet is selected, its tasks loop until interrupt() is called to return to the parent.
7.2 Nested TaskSet
TaskSets can nest multiple levels deep, building complex user journey models:
class LoginTask(TaskSet):
@task
def login(self):
resp = self.client.post("/api/login", json={
"username": "test_user",
"password": "secret"
})
if resp.status_code == 200:
# Login succeeded — enter the shopping flow
self.interrupt() # Return to parent
class ShoppingTask(TaskSet):
tasks = {
BrowseProducts: 5,
AddToCart: 3,
Checkout: 1
}
@task
def stay_here(self):
pass # Fallback task to keep the current level alive
class EcommerceUser(HttpUser):
wait_time = between(1, 3)
host = "https://shop.example.com"
tasks = [LoginTask]Each TaskSet level has its own weight system. interrupt(reschedule=True) can re-trigger task selection immediately after returning.
7.3 interrupt() Usage
interrupt() is the key method for returning from a child TaskSet to its parent. Without it, the agent stays in the current TaskSet forever.
class SessionTimeout(TaskSet):
@task
def check_session(self):
resp = self.client.get("/api/session/check")
if resp.json().get("expired"):
self.interrupt(reschedule=True) # Session expired → return to parent to re-login
@task
def do_work(self):
self.client.get("/api/work")# interrupt() parameter guide
self.interrupt() # Exit and wait for next scheduled task
self.interrupt(reschedule=True) # Exit and immediately re-select a taskForgetting interrupt()
The most common error: forgetting to set an exit condition in a child TaskSet, causing all virtual users to get permanently stuck at that level. Ensure every child TaskSet has at least one path that triggers interrupt().
7.4 on_start and on_stop
Lifecycle hooks at the TaskSet level:
class BrowsingBehavior(TaskSet):
def on_start(self):
"""Run once when this TaskSet is entered"""
self.client.get("/api/products")
def on_stop(self):
"""Run once when this TaskSet is exited via interrupt()"""
self.client.get("/api/logout")
@task
def view_product(self):
self.client.get("/api/products/1")7.5 Chapter Summary
- TaskSet groups related tasks into named behavior blocks;
tasks = {TaskSetClass: weight}on HttpUser selects which behavior to run;interrupt()exits the current TaskSet and returns to the parent;interrupt(reschedule=True)re-selects immediately;on_start()/on_stop()run at TaskSet entry/exit for setup/teardown.
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. What happens if you forget to call interrupt() in a TaskSet?
2. What does interrupt(reschedule=True) do differently from interrupt()?
3. How do you reference a TaskSet from an HttpUser?
4. When does on_stop() in a TaskSet execute?
🛠️ Hands-On Exercises
- Build a
LoginTask → BrowsingTask → CheckoutTasknested hierarchy; verify each phase runs in order. - Add
on_start()andon_stop()to a TaskSet; print logs to confirm they fire at entry and exit. - Deliberately omit
interrupt()from one task in a child TaskSet; observe users getting stuck and fix it.
Proceed to Chapter 8: Event Hooks and Custom Statistics.