2. Priority-Based Resource Scheduling
2.1. Overview
In real-world project management, not all requests for resources are equal. Emergency repairs,
critical work, and VIP tasks often need priority over routine operations. SimPM’s
PriorityResource allows entities to request resources with different
priority levels, ensuring that higher-priority work gets served first—regardless of arrival order.
This tutorial explores priority-based resource scheduling, showing you how to model scenarios where work importance matters as much as work timing.
2.1.1. Key Concepts
- Priority Resource
A
PriorityResourceuses priority values to order requests in the queue. Higher priority requests are served before lower priority ones, even if they arrived later.- Priority Values
Positive values (1, 2, 3…): Standard priority; lower numbers = higher priority
Negative values (-1, -2, -3…): Higher priority; more negative = higher priority
Example: priority=-3 > priority=2 > priority=1
- Service Order
When multiple entities request a resource, SimPM serves them in order of their priority values, not their arrival order. Once served, entities hold the resource until they release it.
2.1.2. Use Cases
Priority-based resources are essential for:
Emergency repairs – Broken equipment gets fixed before routine maintenance
Maintenance scheduling – Critical maintenance preempts regular work
Hospital operations – Emergency patients served before routine appointments
Construction site management – Safety issues get immediate crew attention
IT operations – Critical system failures get immediate technician response
2.2. Scenario: Equipment Supply Queue
Imagine a construction site with a limited equipment depot supplying trucks:
Depot capacity: 3 trucks available
Three contractors requesting trucks:
Contractor A (regular work): priority=1, needs 3 trucks
Contractor B (important project): priority=2, needs 2 trucks
Contractor C (urgent repair): priority=-3 (very high), needs 2 trucks, arrives late
Depot operator: Periodically releases trucks back to the depot (adds supply)
The question: In what order do contractors get served?
Answer: By priority! Contractor C (highest priority) gets trucks first, despite arriving last.
2.3. Detailed Code Example
Here’s the complete priority resource example with step-by-step explanation:
import simpm
from simpm.des import *
# ========================================
# 1. Define Process Functions
# ========================================
def contractor_a_process(env, entity, resource):
"""
Contractor A: Regular work at priority 1 (low).
Requests 3 trucks; will wait due to lower priority.
"""
print(f'{env.now:.2f}: {entity.name} requests 3 trucks (priority 1)')
yield entity.get(resource, 3, priority=1)
print(f'{env.now:.2f}: {entity.name} got 3 trucks')
def contractor_b_process(env, entity, resource):
"""
Contractor B: Important project at priority 2 (medium).
Requests 2 trucks; served after high-priority work.
"""
print(f'{env.now:.2f}: {entity.name} requests 2 trucks (priority 2)')
yield entity.get(resource, 2, priority=2)
print(f'{env.now:.2f}: {entity.name} got 2 trucks')
def contractor_c_process(env, entity, resource):
"""
Contractor C: Urgent repair at priority -3 (highest).
Waits 1 time unit, then requests; gets trucks FIRST due to high priority.
"""
yield entity.do('wait', 1)
print(f'{env.now:.2f}: {entity.name} requests 2 trucks (priority -3 - URGENT)')
yield entity.get(resource, 2, priority=-3)
print(f'{env.now:.2f}: {entity.name} got 2 trucks (SERVED FIRST)')
def depot_operator_process(env, operator, resource):
"""
Depot Operator: Periodically releases trucks back to inventory.
Schedule:
- t=3: Return 3 trucks
- t=6: Return 2 trucks
- t=8: Return 3 trucks
"""
yield operator.do('wait', 3)
print(f'{env.now:.2f}: Depot returns 3 trucks')
yield operator.add(resource, 3)
yield operator.do('wait', 3)
print(f'{env.now:.2f}: Depot returns 2 trucks')
yield operator.add(resource, 2)
yield operator.do('wait', 2)
print(f'{env.now:.2f}: Depot returns 3 trucks')
yield operator.add(resource, 3)
# ========================================
# 2. Set Up Simulation
# ========================================
env = Environment()
# Create entities (contractors and operator)
contractor_a = Entity(env, 'Contractor_A', log=True)
contractor_b = Entity(env, 'Contractor_B', log=True)
contractor_c = Entity(env, 'Contractor_C', log=True)
operator = Entity(env, 'Depot_Operator', log=True)
# Create PriorityResource (depot with limited trucks)
depot = PriorityResource(
env,
'Truck_Depot',
init=0, # Start empty (no trucks)
capacity=3, # Maximum 3 trucks
print_actions=True, # Print all get/add operations
log=True # Log all events
)
# ========================================
# 3. Start Processes
# ========================================
env.process(contractor_a_process(env, contractor_a, depot))
env.process(contractor_b_process(env, contractor_b, depot))
env.process(operator_process(env, operator, depot))
env.process(contractor_c_process(env, contractor_c, depot))
# ========================================
# 4. Run Simulation
# ========================================
simpm.run(env, dashboard=True)
2.3.1. How It Works
Timeline of Events:
t=0.00: Contractor_A requests 3 trucks (priority 1)
→ Waits (depot empty)
t=0.00: Contractor_B requests 2 trucks (priority 2)
→ Waits (depot empty, lower priority than C)
t=0.00: Depot_Operator starts work
→ Will return trucks at t=3, t=6, t=8
t=1.00: Contractor_C requests 2 trucks (priority -3 - HIGHEST)
→ Waits (depot empty, but is now first in queue)
t=3.00: Depot returns 3 trucks
→ Contractor_C gets 2 trucks FIRST (priority -3)
→ 1 truck remains in depot
t=6.00: Depot returns 2 trucks
→ 3 trucks now available
→ Contractor_B gets 2 trucks (priority 2)
→ 1 truck remains
t=8.00: Depot returns 3 trucks
→ 4 trucks available
→ Contractor_A gets 3 trucks (priority 1)
→ 1 truck remains
Key Observations:
Priority overrides arrival order: Contractor C arrives at t=1, but gets trucks at t=3 when they become available, because priority=-3 > priority=2 > priority=1.
Queue management: The resource automatically maintains a priority queue and serves highest-priority requests first when capacity becomes available.
Waiting times: - Contractor A: Arrives t=0, served t=8 (waits 8 time units) - Contractor B: Arrives t=0, served t=6 (waits 6 time units) - Contractor C: Arrives t=1, served t=3 (waits only 2 time units, thanks to high priority!)
2.4. Advanced Topics
Multiple Priority Levels
You can use any integer priority value. For example, in a hospital:
routine_checkup = Priority(priority=10) # Low priority
important_surgery = priority(priority=0) # Medium priority
emergency_trauma = priority(priority=-100) # Very high priority
Combining with Other Resource Types
Priority resources work alongside regular resources:
# Regular resource (FIFO queue)
general_crew = Resource(env, 'General_Crew', capacity=2)
# Priority resource (ordered by priority value)
emergency_crew = PriorityResource(env, 'Emergency_Crew', capacity=1)
# Entity requests both
yield entity.get(general_crew, 1) # Gets in line, first come first served
yield entity.get(emergency_crew, 1) # Gets in line by priority
Dynamic Priority Changes
Priorities can be adjusted during simulation based on conditions:
# Initial request at low priority
yield entity.get(resource, 1, priority=10)
# If conditions change, higher-priority request can interrupt (see PreemptiveResource)
yield entity.get(resource, 1, priority=-10, preempt=True)
2.5. Try It Yourself
Experiment 1: Change Priority Values
What happens if you change Contractor C’s priority from -3 to 3? Now it has the lowest priority! Try it and observe the new service order.
Experiment 2: Add More Contractors
Add a fourth contractor with priority=0 (between B and C). How does this change the service order?
Experiment 3: Increase Depot Capacity
Change capacity=3 to capacity=5. Do all contractors get served immediately when
trucks are available?
Experiment 4: Use the Dashboard
Enable the dashboard (default: dashboard=True). Explore:
- Timeline view: See when each contractor gets trucks
- Queue view: See how the priority queue changes over time
- Resource utilization: How many trucks are in use at each time?
2.6. Real-World Example: Earthmoving with Scheduled Maintenance
A practical application of priority scheduling: managing equipment repairs in an earthmoving project.
Scenario:
A construction site has: - 2 trucks (small 80-unit, large 100-unit capacity) - 1 shared loader (bottleneck resource) - 1 repair person who maintains the loader based on usage
The Challenge:
Trucks request the loader with normal priority. When the loader accumulates 10 worked hours, the repair person needs to service it. Using a PriorityResource, we give the repair person high priority (-3) so repairs happen quickly, without waiting for truck loading to finish.
Code Example (Simplified):
import simpm
import simpm.des as d
import simpm.dist as dist
def truck_process(truck, loader, dumped_dirt, worked_hours):
"""Truck cycles: load, haul, dump, return."""
while True:
# Request loader with normal priority (priority=2)
yield truck.get(loader, 1, priority=2)
loading_time = truck.loading_dur.sample()
yield truck.do('load', loading_time)
yield truck.add(worked_hours, loading_time) # Track hours for repairs
yield truck.put(loader, 1)
yield truck.do('haul', truck.hauling_dur.sample())
yield truck.do('dump', truck.dumping_dur)
yield truck.add(dumped_dirt, truck.capacity)
yield truck.do('return', 8)
def repair_process(repair_man, loader, worked_hours):
"""Repair person monitors loader hours."""
while True:
# Wait until 10 hours accumulated
yield repair_man.get(worked_hours, 10)
# Request with HIGH PRIORITY to interrupt trucks
yield repair_man.get(loader, 1, priority=-3)
yield repair_man.do('repair', 10)
yield repair_man.put(loader, 1)
# Set up environment
env = d.Environment()
loader = d.PriorityResource(env, 'loader', init=1)
dumped_dirt = d.Resource(env, 'dirt', init=0, capacity=2000)
worked_hours = d.Resource(env, 'worked_hours', init=0)
small_truck = d.Entity(env, 'small_truck')
small_truck.loading_dur = dist.uniform(4, 5)
small_truck.hauling_dur = dist.uniform(10, 14)
small_truck.dumping_dur = 4
small_truck.capacity = 80
large_truck = d.Entity(env, 'large_truck')
large_truck.loading_dur = dist.uniform(4, 7)
large_truck.hauling_dur = dist.uniform(12, 16)
large_truck.dumping_dur = 5
large_truck.capacity = 100
repair_man = d.Entity(env, 'repair_person')
env.process(truck_process(small_truck, loader, dumped_dirt, worked_hours))
env.process(truck_process(large_truck, loader, dumped_dirt, worked_hours))
env.process(repair_process(repair_man, loader, worked_hours))
simpm.run(env, dashboard=False)
Results:
With PriorityResource, repairs are scheduled with high priority but still queue-based: - When repair is needed (10 worked hours), the repair person waits for the next
available loader opportunity
Current truck loading finishes, then repair proceeds immediately
Trucks never wait long because repairs have priority=-3 > normal priority=2
This balances maintenance needs with productivity
Actual Results (Random Seed 42):
Metric |
Value |
|---|---|
Total Project Time |
381.16 minutes (6.35 hours) |
Total Dirt Dumped |
1,960 units |
Small Truck Cycles Small Truck Output |
51 cycles 4,080 units |
Large Truck Cycles Large Truck Output |
43 cycles 4,300 units |
Total Loader Requests Avg Truck Wait Time Max Truck Wait Time |
34 1.64 minutes 7.57 minutes |
Repairs Performed Repair Interval Total Repair Time |
10 maintenance Every 10 hours 100 minutes (4.4%) |
Key Results:
Priority Queue Works: High-priority repairs (priority=-3) queue ahead of normal truck loading (priority=2). Repairs happen at the first opportunity when loader becomes free.
No Interruptions: Unlike PreemptiveResource, truck loading finishes completely before repairs begin. The large truck completes its 5-minute load even if repair is waiting.
Predictable Schedule: 10 repairs occurring roughly every 38 minutes shows the system successfully tracks cumulative work hours and triggers maintenance at regular intervals.
Moderate Congestion: Average truck wait time of 1.64 minutes is manageable. Single loader is a bottleneck, but not severely. Adding a second loader would provide only modest speedup.
Efficient Coordination: Both trucks effectively share the single loader despite different loading times (small: 4-5 min, large: 4-7 min). Small truck completes more cycles due to shorter per-cycle duration.
Key Advantage of PriorityResource Here:
Instead of ad-hoc repair scheduling, the high-priority queue ensures repairs are done at the first opportunity when the loader becomes free. This balances maintenance needs with productivity— repairs happen quickly but don’t waste work already invested in truck cycles.
See the complete working example: example/repair_earthmoving.py
2.7. Next Steps
Learn about preemptive resources where high-priority work can INTERRUPT low-priority work in progress: Preemptive Resource Scheduling