Processes with Queues
Nine processes in which entities wait for a resource or move through steps: orders that wait for busy packers, a machine that slows as it wears, a capacity that drops while the queue grows, callers who hang up, urgent tickets served first, shoppers who pay or abandon, visitors who drop out at each sign-up step, bets that are settled, and audits that need a follow-up. Each entry is a complete file in three forms.
Before You Start
The commands run from the root of a clone of the repository, where the files are in examples/gallery/:
An entry that needs a service or an extra says so. Services for the Examples shows how to start the services. A file with a fixed random_seed and factor: 0 prints the same records on every run, and each output block below holds the first events of the YAML file. The Builder and Low-level files publish the same records.
Entries
Orders wait in a queue when all packers are busy
A shop has 3 packers. Orders arrive about once a minute, and packing takes a normal time with a mean of 240 s and a standard deviation of 60 s. The run lasts 2 hours. When all three packers are busy an order waits, and the minimal statistics publish the queue length and the units in use.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The gaps and the service times come from Sampler.sample on a DistributionConfig whose stream is arrival.orders and service.pack, the sequences the blueprint uses for its arrivals and services.
| examples/gallery/orders_wait_for_busy_packers_low_level.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | |
A machine slows down as it wears, then is repaired
A press stamps one blank at a time. Stamping takes a normal time with a mean of 10 s. Wear raises the mean to 12, 14 and 16 s at 1, 2 and 3 hours, and a repair at 4 hours sets it back to 10 s. The wear is written as steps of a scenario.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The gaps and the service times come from Sampler.sample on a DistributionConfig whose stream is arrival.blanks and service.stamp, the sequences the blueprint uses for its arrivals and services.
| examples/gallery/machine_slows_as_it_wears_low_level.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | |
Capacity drops to one at 20 seconds, and the queue grows
A shop has 3 packers. An order arrives about every second, and packing takes a normal time with a mean of 2.5 s. A scenario step at 20 s sets the capacity to 1, so the orders queue. The statistics publish the capacity and the queue length every second.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The gaps and the service times come from Sampler.sample on a DistributionConfig whose stream is arrival.orders and service.pack, the sequences the blueprint uses for its arrivals and services.
| examples/gallery/capacity_drops_and_queue_grows_low_level.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | |
Callers hang up when they wait for an agent for longer than they will tolerate
Calls arrive at 54 an hour and two agents answer about 30 an hour, so a queue builds. A caller who waits longer than their patience, 1 to 5 minutes, hangs up. A scenario step adds two agents after half an hour, so calls wait less and fewer callers hang up.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as tasks.answer_call.patience. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's.
| examples/gallery/callers_hang_up_after_waiting_too_long_low_level.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | |
Urgent support tickets are served before older tickets of lower priority
One agent solves a ticket in about 50 seconds, and a ticket arrives about every 55 seconds, so tickets wait. The agent's queue is ordered by priority, so a ticket of priority 1 (10 percent of them) waits less than one of priority 3 (60 percent).
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as arrivals.tickets.attributes.priority. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's.
| examples/gallery/urgent_tickets_are_served_first_low_level.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | |
A shopper keeps adding items to a cart, then pays or abandons it
A shopper adds an item every 5 to 30 seconds, and after each item 60 percent add another, 25 percent pay and 15 percent leave. Two tills serve the payments, each for about 25 seconds, so shoppers queue to pay when both are busy.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as tasks.add_item.service_time. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's. The branch of each step is chosen by a Router whose random sequence is Sampler.generator("route.add_item"), the sequence of the blueprint's next.
| examples/gallery/shoppers_add_items_then_pay_or_abandon_low_level.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | |
Visitors drop out at each step of a signup funnel
Of every 100 visitors, 40 sign up, 20 of those start a trial, and 5 of those pay. A visitor who drops out ends in one left task, whose record names the step the visitor left after.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as route.{step} with the place of the task filled in. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's. The branch of each step is chosen by a Router whose random sequence is Sampler.generator("route.{step}"), and one more for each step, the sequence of the blueprint's next. The gaps between arrivals come from Sampler.sample on a DistributionConfig whose stream is arrival.visitors, the sequence the blueprint uses for its arrivals.
Each bet is settled after the match, and a winner is paid the stake times the odds
A bet is placed with a stake and odds. One to two minutes later it is settled: 45 percent win and are paid the stake times the odds, the rest lose and are paid nothing, and the settled record repeats the bet id.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as tasks.place_bet.payload.stake, tasks.place_bet.payload.odds and tasks.settle_bet.vars.won and 1 more. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's. The gaps between arrivals come from Sampler.sample on a DistributionConfig whose stream is arrival.bets, the sequence the blueprint uses for its arrivals.
An audit that finds an issue needs a follow-up, which waits for the same two auditors
An audit of one of 150 merchants is due about every 3 hours and takes an auditor about 4 hours, and 15 percent find an issue. A follow-up takes about an hour and goes to the back of the same queue, so audits and follow-ups compete for the two auditors.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as tasks.audit.payload.merchant and tasks.audit.payload.finding. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's.
| examples/gallery/audits_with_findings_need_a_follow_up_low_level.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | |