Priority and Preemption
Task priority, preemption and breakdowns are the forms of a resource that rank waiting requests and take units from tasks.
How to Use It
Task Priority
Under queue: priority, each task gives its requests a priority: a number, the same for every run of the task; an expression, read when the task joins the queue, such as attr.tier for the entity's attribute tier; or, in the builder, a function of the task id and the entity's attributes. The attributes exist before the request queues, and the task's own payload does not, so a priority cannot read it; an expression can read the previous task's payload as payload.<field>. The lowest priority is served first, and a task with no priority ranks 0, as a SimPy PriorityRequest does. Equal priorities are served first in, first out, which is the order of SimPy's PriorityResource: it ranks a request by (priority, time, not preempt), so among equal priorities and times a request that may preempt goes before one with preempt: false. The tests check it, ties included, in all three APIs (SimPy Compatibility).
A low-level process passes the priority to the request: packers.request(priority=entity.attributes["tier"]), as the queue-order example above does; a request with no priority has priority 0. A resource whose queue is fifo or lifo ignores it.
A priority on a task whose resource does not have queue: priority is refused: when the blueprint loads, or when run() starts. Priorities shows what priority does to waits.
Preemption
On a resource with preempt: true, which needs queue: priority, a request that finds every unit busy takes a unit from a task of a higher priority value, as SimPy's PreemptiveResource does. The task that loses the unit is chosen by SimPy's rule: the user whose (priority, request time, may not preempt) sorts last, and only when that sorts after the new request, so equal priorities do not preempt; the one exception is a user whose request was made at the same moment as the new one with preempt: false, which sorts after a request that may preempt. The task publishes preempted with the resource's name, the key of the entity that took the unit (preempted_by) and the time the task was granted the unit (usage_since), and follows its on_interrupt, as an interrupt would (Interruptions); a task with preempt: false never takes a unit this way. The interruptions example lets express orders preempt regular ones:
| examples/yaml/interruptions.yaml:packers | |
|---|---|
| examples/builder/interruptions_example.py:packers | |
|---|---|
| examples/builder/interruptions_example.py:pack | |
|---|---|
DynamicResource(env, "Shop", "packers", queue="priority", preempt=True) builds the resource, and request(priority, preempt=True) asks for a unit; the process that loses its unit receives simpy.Interrupt with a SimPy Preempted cause, whose resource, by (the process that took the unit) and usage_since say what happened.
Breakdowns
A breakdown makes a resource fail at random and be repaired. time_to_failure is the time from the start, or from a repair, to the next failure, on calendar time, busy or idle; repair is how long a repair takes. While the resource is down its effective capacity is 0 and no request is granted:
| examples/low-level/breakdowns_example.py:station | |
|---|---|
Start run_breakdowns(env, station, sampler, work="interrupt") as a SimPy process beside the arrivals. station.fail() and station.repair() put a resource down and back by hand.
work says what happens to the tasks being served: interrupt, the default, interrupts each with the cause breakdown, and it follows its on_interrupt; finish lets them finish. Each failure and repair publishes an event keyed by the resource's name, with status down or repaired and reason: failure. Breakdowns checks the downtime of the example, and Interruptions explains on_interrupt.
Example: Interruptions
The interruptions example: express orders preempt regular ones, and a fire drill at 60 seconds interrupts the order being packed; each resumes with the packing time it had left. It needs no Docker service and ends on its own after 120 simulation seconds.
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
The whole file is examples/yaml/interruptions.yaml.
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
The whole file is examples/builder/interruptions_example.py.
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
The whole file is examples/low-level/interruptions_example.py.