Pallet preparation - Preemption no restart

SimPype features used in this example: Random variables, Resource custom model, Pipe custom model, Log custom message properties.

The scenario of the simulation is the following:

|Urgent order| -\
                 ) -> |Worker|
|Normal order| -/

This example models a working day (8 hours) of a worker in a warehouse. The worker’s job is to prepare a pallet upon receiving an order. There are two types of orders:

  • Urgent
  • Normal

Each order comprises a number of items to be packed on the same pallet. Urgent orders preempt normal orders. This means that if an urgent order is received while the worker is preparing the pallet for a normal order, the worker will stop what is doing and will immedietaly start preparing the pallet for the urgent order. Once the urgent pallet is prepare, the worker will resume the preparation of the pallet of the normal order.

This kind of interaction is usually called preemption with no restart.

The scenario is so implemented with SimPype:

import simpype
import random


# [Mandatory] Create a SimPype simulation object
sim = simpype.Simulation(id = 'pallet_norestart')
# [Optional] Fix the seed used by the pseudo-random generator
sim.seed = 42
# [Optional] Configure the log directory. 
# [Default] Log are store by default in the 'current working directory/log'
sim.log.dir = 'log'
# [Optional] Disable the logging to file and print to console instead
#sim.log.file = False
#sim.log.print = True
# [Optional] Log custom message properties
sim.log.property('items')
# [Optional] Configure the path containting the models for the simulation. 
# [Default] Current working directory
sim.model.dir = 'examples/model'

# Create a generator
urgent = sim.add_generator(id = 'urgent')
# Assign an arrival time
urgent.random['arrival'] = {
	0: lambda: random.expovariate(1.0 / 3600)
}
urgent.message.property['priority'] = 'urgent'
urgent.message.property['items'] = {
	0: lambda: random.randint(1, 5)
}
# Create a generator
normal = sim.add_generator(id = 'normal')
# Assign an arrival time
normal.random['arrival'] = {
	0: lambda: random.expovariate(1.0 / 300)
}
normal.message.property['priority'] = 'normal'
normal.message.property['items'] = {
	0: lambda: random.randint(10, 30)
}

# Add a resource
worker = sim.add_resource(id = 'worker', model = 'r_preemption', pipe = 'p_preemption')
worker.random['service'] = {
	0: lambda: random.expovariate(1.0 / 10)
}

# Add a pipeline connecting the generator to the resource
p0 = sim.add_pipeline(urgent, worker)
p1 = sim.add_pipeline(normal, worker)

# Run until t=28800 (8 hours)
sim.run(until = 28800)

Where pipe model p_preemption is so implemented:

import simpype


class PriorityPreemption(simpype.Pipe):
	def __init__(self, sim, resource, id):
		super().__init__(sim, resource, id)		
		self.add_queue(id = 'preempted')
		self.add_queue(id = 'urgent')
		self.add_queue(id = 'normal')

	@simpype.pipe.dequeue
	def dequeue(self):
		if len(self.queue['urgent']) > 0:
			return self.queue['urgent'].pop()
		elif len(self.queue['preempted']) > 0:
			return self.queue['preempted'].pop()
		else:
			return self.queue['normal'].pop()

	@simpype.pipe.enqueue
	def enqueue(self, message):
		if message.property['priority'].value == 'urgent':
			m = self.queue['urgent'].push(message)
			
			tlist = [t for t in self.resource.task.values() if t.process.is_alive and t.message.property['priority'].value != 'urgent']
			# If the resource is busy, preempt the current task
			if len(tlist) > 0:
				#task = max(tlist, key = lambda task: task.message.property['priority'].value)
				task = tlist[0]
				task.interrupt(cause = 'preempted')
				# This if is useful only in case of preemption with no restart
				if 'wait' in task.message.property:
					task.message.property['wait'] = task.message.property['wait'].value - (task.interrupted - task.started)
				self.queue['preempted'].push(task.message)
		else:
			m = self.queue['normal'].push(message)

		return m


# Do NOT remove
pipe = lambda *args: PriorityPreemption(*args)

And resource model r_preemption is so implemented:

import simpype


class ResourcePreemption(simpype.Resource):
	def __init__(self, sim, id, capacity = 1, pipe = None):
		super().__init__(sim, id, capacity, pipe)
		# This is overwritten later in the simulaiton file
		self.random['service'] = {
			0: lambda: 1.0
		}

	@simpype.resource.service	
	def service(self, message):
		if 'wait' not in message.property:
			message.property['wait'] = message.property['items'].value * self.random['service'].value
		yield self.env.timeout(message.property['wait'].value)


# Do NOT remove
resource = lambda *args: ResourcePreemption(*args)

sim.cfg stored under the log folder contains:

Simulation Seed: 42
Simulation Time: 28800.000000000
Execution Time: 0.060198644

sim.log stored under the log folder contains:

timestamp,message,seq_num,resource,event,items
27.285721382,normal,0,worker,pipe.in,23
27.285721382,normal,0,worker,pipe.out,23
36.975335053,normal,1,worker,pipe.in,17
49.913040803,normal,0,worker,resource.serve,23
49.913040803,normal,1,worker,pipe.out,17
54.485089429,normal,1,worker,resource.serve,17
248.149993412,normal,2,worker,pipe.in,16
248.149993412,normal,2,worker,pipe.out,16
441.493859789,normal,2,worker,resource.serve,16
625.805024250,normal,3,worker,pipe.in,23
625.805024250,normal,3,worker,pipe.out,23
700.512949940,normal,4,worker,pipe.in,10
830.461026699,normal,3,worker,resource.serve,23
830.461026699,normal,4,worker,pipe.out,10
847.855816062,normal,4,worker,resource.serve,10
1127.160757415,normal,5,worker,pipe.in,23
1127.160757415,normal,5,worker,pipe.out,23
1166.027599075,normal,5,worker,resource.serve,23
1251.929283365,normal,6,worker,pipe.in,20
1251.929283365,normal,6,worker,pipe.out,20
1284.275103075,normal,7,worker,pipe.in,21
1347.512993521,normal,6,worker,resource.serve,20
1347.512993521,normal,7,worker,pipe.out,21
1541.899381582,normal,7,worker,resource.serve,21
1848.441225565,normal,8,worker,pipe.in,11
1848.441225565,normal,8,worker,pipe.out,11
1932.961092209,normal,8,worker,resource.serve,11
2240.943354699,normal,9,worker,pipe.in,22
2240.943354699,normal,9,worker,pipe.out,22
2265.566852517,normal,10,worker,pipe.in,30
2317.278253108,normal,9,worker,resource.serve,22
2317.278253108,normal,10,worker,pipe.out,30
2554.675714055,normal,11,worker,pipe.in,28
2618.740849180,normal,12,worker,pipe.in,12
2632.813111258,normal,13,worker,pipe.in,17
2910.792233711,normal,10,worker,resource.serve,30
2910.792233711,normal,11,worker,pipe.out,28
3077.745021529,normal,14,worker,pipe.in,17
3681.804460196,normal,15,worker,pipe.in,22
3779.512534186,normal,16,worker,pipe.in,30
4090.875545150,normal,11,worker,resource.serve,28
4090.875545150,normal,12,worker,pipe.out,12
4112.177708608,normal,12,worker,resource.serve,12
4112.177708608,normal,13,worker,pipe.out,17
4186.794914503,normal,13,worker,resource.serve,17
4186.794914503,normal,14,worker,pipe.out,17
4318.442414000,normal,17,worker,pipe.in,30
4340.666385782,normal,18,worker,pipe.in,30
4375.357825977,normal,14,worker,resource.serve,17
4375.357825977,normal,15,worker,pipe.out,22
4396.977101389,normal,19,worker,pipe.in,15
4583.091251682,normal,20,worker,pipe.in,18
4662.700806454,normal,15,worker,resource.serve,22
4662.700806454,normal,16,worker,pipe.out,30
4969.195980592,normal,16,worker,resource.serve,30
4969.195980592,normal,17,worker,pipe.out,30
5213.417601642,normal,17,worker,resource.serve,30
5213.417601642,normal,18,worker,pipe.out,30
5559.605238443,normal,18,worker,resource.serve,30
5559.605238443,normal,19,worker,pipe.out,15
5837.190248640,normal,19,worker,resource.serve,15
5837.190248640,normal,20,worker,pipe.out,18
5950.673162214,normal,21,worker,pipe.in,17
6106.489838444,normal,20,worker,resource.serve,18
6106.489838444,normal,21,worker,pipe.out,17
6384.438244483,normal,21,worker,resource.serve,17
6468.132158445,normal,22,worker,pipe.in,22
6468.132158445,normal,22,worker,pipe.out,22
6520.264945496,normal,22,worker,resource.serve,22
6561.618408373,normal,23,worker,pipe.in,28
6561.618408373,normal,23,worker,pipe.out,28
6667.420973560,normal,23,worker,resource.serve,28
7188.751262326,normal,24,worker,pipe.in,30
7188.751262326,normal,24,worker,pipe.out,30
7396.234526404,normal,25,worker,pipe.in,30
7580.453185706,normal,26,worker,pipe.in,18
7625.571122030,normal,27,worker,pipe.in,27
7836.772789002,normal,24,worker,resource.serve,30
7836.772789002,normal,25,worker,pipe.out,30
7857.863514232,normal,28,worker,pipe.in,23
8018.237158385,urgent,0,worker,pipe.in,4
8018.237158385,normal,25,worker,pipe.in,30
8018.237158385,normal,25,worker,resource.preempted,30
8018.237158385,urgent,0,worker,pipe.out,4
8255.201029505,urgent,0,worker,resource.serve,4
8255.201029505,normal,25,worker,pipe.out,30
8486.062775099,normal,25,worker,resource.serve,30
8486.062775099,normal,26,worker,pipe.out,18
8512.862063805,normal,26,worker,resource.serve,18
8512.862063805,normal,27,worker,pipe.out,27
8542.177775118,normal,29,worker,pipe.in,11
8696.532862972,normal,27,worker,resource.serve,27
8696.532862972,normal,28,worker,pipe.out,23
8734.682332207,normal,28,worker,resource.serve,23
8734.682332207,normal,29,worker,pipe.out,11
8753.858847901,normal,29,worker,resource.serve,11
9134.384368328,normal,30,worker,pipe.in,23
9134.384368328,normal,30,worker,pipe.out,23
9246.107955706,normal,30,worker,resource.serve,23
9406.590378189,normal,31,worker,pipe.in,29
9406.590378189,normal,31,worker,pipe.out,29
9625.000973941,normal,31,worker,resource.serve,29
9636.118275916,urgent,1,worker,pipe.in,5
9636.118275916,urgent,1,worker,pipe.out,5
9636.695647801,urgent,1,worker,resource.serve,5
11072.273154374,normal,32,worker,pipe.in,13
11072.273154374,normal,32,worker,pipe.out,13
11172.368493323,normal,32,worker,resource.serve,13
11415.711210823,normal,33,worker,pipe.in,18
11415.711210823,normal,33,worker,pipe.out,18
11490.551853380,normal,33,worker,resource.serve,18
11854.791807040,normal,34,worker,pipe.in,19
11854.791807040,normal,34,worker,pipe.out,19
11969.671582824,normal,34,worker,resource.serve,19
12025.946051615,normal,35,worker,pipe.in,18
12025.946051615,normal,35,worker,pipe.out,18
12284.304693889,normal,35,worker,resource.serve,18
13097.414730980,normal,36,worker,pipe.in,26
13097.414730980,normal,36,worker,pipe.out,26
13628.911360163,normal,36,worker,resource.serve,26
13828.688303491,normal,37,worker,pipe.in,19
13828.688303491,normal,37,worker,pipe.out,19
13963.320707091,normal,37,worker,resource.serve,19
14381.609213366,normal,38,worker,pipe.in,16
14381.609213366,normal,38,worker,pipe.out,16
14431.368664391,normal,39,worker,pipe.in,27
14611.630514253,normal,38,worker,resource.serve,16
14611.630514253,normal,39,worker,pipe.out,27
15301.919839754,normal,39,worker,resource.serve,27
15351.857926270,normal,40,worker,pipe.in,10
15351.857926270,normal,40,worker,pipe.out,10
15418.919364046,normal,40,worker,resource.serve,10
15625.954626627,normal,41,worker,pipe.in,13
15625.954626627,normal,41,worker,pipe.out,13
15900.211575902,normal,41,worker,resource.serve,13
16419.894225302,normal,42,worker,pipe.in,19
16419.894225302,normal,42,worker,pipe.out,19
16472.255249139,normal,42,worker,resource.serve,19
16502.009163586,normal,43,worker,pipe.in,28
16502.009163586,normal,43,worker,pipe.out,28
16527.081938335,normal,43,worker,resource.serve,28
16734.230083868,urgent,2,worker,pipe.in,4
16734.230083868,urgent,2,worker,pipe.out,4
16886.870413510,urgent,2,worker,resource.serve,4
17382.962150916,normal,44,worker,pipe.in,27
17382.962150916,normal,44,worker,pipe.out,27
17420.064169340,normal,44,worker,resource.serve,27
17818.480204946,normal,45,worker,pipe.in,25
17818.480204946,normal,45,worker,pipe.out,25
17863.599108038,normal,45,worker,resource.serve,25
18698.863905021,normal,46,worker,pipe.in,26
18698.863905021,normal,46,worker,pipe.out,26
18841.903452458,normal,46,worker,resource.serve,26
19316.598070304,normal,47,worker,pipe.in,16
19316.598070304,normal,47,worker,pipe.out,16
19541.810884695,normal,47,worker,resource.serve,16
20109.755390857,normal,48,worker,pipe.in,16
20109.755390857,normal,48,worker,pipe.out,16
20191.218996064,normal,48,worker,resource.serve,16
20484.183976048,normal,49,worker,pipe.in,30
20484.183976048,normal,49,worker,pipe.out,30
20624.427862433,normal,50,worker,pipe.in,24
20663.120408863,normal,51,worker,pipe.in,17
20682.970649833,normal,52,worker,pipe.in,10
20949.215107980,normal,53,worker,pipe.in,17
21173.803986105,normal,49,worker,resource.serve,30
21173.803986105,normal,50,worker,pipe.out,24
21175.536022348,normal,50,worker,resource.serve,24
21175.536022348,normal,51,worker,pipe.out,17
21215.555329820,normal,54,worker,pipe.in,11
21293.552750087,normal,55,worker,pipe.in,11
21384.713698988,normal,51,worker,resource.serve,17
21384.713698988,normal,52,worker,pipe.out,10
21392.062998951,normal,52,worker,resource.serve,10
21392.062998951,normal,53,worker,pipe.out,17
21438.271515829,normal,53,worker,resource.serve,17
21438.271515829,normal,54,worker,pipe.out,11
21559.884190617,normal,54,worker,resource.serve,11
21559.884190617,normal,55,worker,pipe.out,11
21586.405170112,normal,55,worker,resource.serve,11
21882.606337410,normal,56,worker,pipe.in,14
21882.606337410,normal,56,worker,pipe.out,14
22182.251464310,normal,56,worker,resource.serve,14
22268.109752762,normal,57,worker,pipe.in,28
22268.109752762,normal,57,worker,pipe.out,28
22460.088958772,normal,58,worker,pipe.in,23
22523.457126729,normal,59,worker,pipe.in,13
22698.007387668,normal,57,worker,resource.serve,28
22698.007387668,normal,58,worker,pipe.out,23
22798.613185133,normal,58,worker,resource.serve,23
22798.613185133,normal,59,worker,pipe.out,13
22828.835347781,urgent,3,worker,pipe.in,1
22828.835347781,normal,59,worker,pipe.in,13
22828.835347781,normal,59,worker,resource.preempted,13
22828.835347781,urgent,3,worker,pipe.out,1
22846.203791242,normal,60,worker,pipe.in,13
22864.962010388,normal,61,worker,pipe.in,20
22870.290807252,urgent,3,worker,resource.serve,1
22870.290807252,normal,59,worker,pipe.out,13
22908.904002618,normal,59,worker,resource.serve,13
22908.904002618,normal,60,worker,pipe.out,13
22923.946671982,normal,60,worker,resource.serve,13
22923.946671982,normal,61,worker,pipe.out,20
22966.483874513,normal,61,worker,resource.serve,20
23348.683469526,normal,62,worker,pipe.in,27
23348.683469526,normal,62,worker,pipe.out,27
23496.637166619,normal,62,worker,resource.serve,27
23527.279274699,normal,63,worker,pipe.in,18
23527.279274699,normal,63,worker,pipe.out,18
23713.598718948,normal,64,worker,pipe.in,12
23889.226158169,normal,65,worker,pipe.in,27
23900.840043944,normal,63,worker,resource.serve,18
23900.840043944,normal,64,worker,pipe.out,12
23920.138030907,normal,66,worker,pipe.in,27
24027.556353701,normal,64,worker,resource.serve,12
24027.556353701,normal,65,worker,pipe.out,27
24462.555151011,normal,67,worker,pipe.in,17
24517.123645165,normal,68,worker,pipe.in,25
24714.086313499,normal,69,worker,pipe.in,22
24965.441137940,normal,65,worker,resource.serve,27
24965.441137940,normal,66,worker,pipe.out,27
25014.011185055,normal,66,worker,resource.serve,27
25014.011185055,normal,67,worker,pipe.out,17
25014.377994824,normal,67,worker,resource.serve,17
25014.377994824,normal,68,worker,pipe.out,25
25138.124986531,normal,68,worker,resource.serve,25
25138.124986531,normal,69,worker,pipe.out,22
25412.281436852,normal,70,worker,pipe.in,24
25513.027847554,normal,71,worker,pipe.in,27
25712.482462920,normal,69,worker,resource.serve,22
25712.482462920,normal,70,worker,pipe.out,24
25838.326464180,normal,72,worker,pipe.in,16
25872.523850704,normal,70,worker,resource.serve,24
25872.523850704,normal,71,worker,pipe.out,27
25943.921322946,normal,73,worker,pipe.in,28
26343.164663794,normal,74,worker,pipe.in,11
26756.633427859,normal,75,worker,pipe.in,11
26772.066368153,normal,76,worker,pipe.in,25
26807.921685859,normal,71,worker,resource.serve,27
26807.921685859,normal,72,worker,pipe.out,16
26856.913340344,urgent,4,worker,pipe.in,2
26856.913340344,normal,72,worker,pipe.in,16
26856.913340344,normal,72,worker,resource.preempted,16
26856.913340344,urgent,4,worker,pipe.out,2
26871.091901142,urgent,4,worker,resource.serve,2
26871.091901142,normal,72,worker,pipe.out,16
26981.725645489,normal,77,worker,pipe.in,15
27003.020242686,normal,78,worker,pipe.in,12
27067.734039713,urgent,5,worker,pipe.in,2
27067.734039713,normal,72,worker,pipe.in,16
27067.734039713,normal,72,worker,resource.preempted,16
27067.734039713,urgent,5,worker,pipe.out,2
27124.541501249,urgent,5,worker,resource.serve,2
27124.541501249,normal,72,worker,pipe.out,16
27185.374749646,normal,72,worker,resource.serve,16
27185.374749646,normal,73,worker,pipe.out,28
27340.395539196,normal,79,worker,pipe.in,28
27421.475088222,normal,73,worker,resource.serve,28
27421.475088222,normal,74,worker,pipe.out,11
27527.730440170,normal,74,worker,resource.serve,11
27527.730440170,normal,75,worker,pipe.out,11
27587.503528787,normal,75,worker,resource.serve,11
27587.503528787,normal,76,worker,pipe.out,25
27611.200031467,normal,80,worker,pipe.in,26
27725.301496893,normal,81,worker,pipe.in,18
27793.846028968,normal,82,worker,pipe.in,20
27806.574169467,normal,76,worker,resource.serve,25
27806.574169467,normal,77,worker,pipe.out,15
27875.658827669,normal,83,worker,pipe.in,30
27882.148157306,normal,77,worker,resource.serve,15
27882.148157306,normal,78,worker,pipe.out,12
27927.754931762,normal,78,worker,resource.serve,12
27927.754931762,normal,79,worker,pipe.out,28
27982.660059338,normal,84,worker,pipe.in,12
27985.467794470,normal,85,worker,pipe.in,29
28318.013410298,normal,79,worker,resource.serve,28
28318.013410298,normal,80,worker,pipe.out,26