The Bakery Rush
The Bakery Rush: two ovens, thirteen orders, one queue - and the morning is decided before the first tray goes in, by ENQUEUE ORDER. A bakery is a queue wearing an apron: the plan is the queue, the concurrency limit is the ovens, and the discipline (who bakes first) is policy you choose, not fate. We run the same morning twice - first-come-first-served with the wedding cake up front, then shortest-bake-first - and measure customer sadness. Queue theory has opinions about …
Testing & Verification
Round 18
Rosa Gutiérrez
exit 0
bundle exec ruby examples/bakery_rush.rb
a real captured run
THE BAKERY RUSH (a bakery is a queue wearing an apron)
monday, first-come-first-served (two cakes hog BOTH ovens at 6am):
mean wait 210ms; customers lost to the cafe next door: 8
walked out: croissant #1 (waited 184ms, patience 150ms)
walked out: croissant #2 (waited 205ms, patience 150ms)
walked out: croissant #3 (waited 205ms, patience 150ms)
walked out: croissant #4 (waited 225ms, patience 150ms)
walked out: croissant #5 (waited 226ms, patience 150ms)
walked out: croissant #6 (waited 246ms, patience 150ms)
walked out: eclair #1 (waited 310ms, patience 300ms)
walked out: eclair #2 (waited 327ms, patience 300ms)
cakes: done at 183ms and 205ms - both on time
tuesday, shortest-bake-first (same ovens, same orders, new discipline):
mean wait 79ms; customers lost to the cafe next door: 0
cakes: done at 326ms and 386ms - both on time
nothing about the bakery changed overnight - not the ovens, not
the orders, not the bake times. only the DISCIPLINE: monday
baked in arrival order and the wedding cake sat in an oven for
200ms while croissant customers (patience: 150ms) studied the
cafe across the street. tuesday baked shortest-first, because
shortest-job-first provably minimizes mean wait - and the cake
was never actually urgent: ordered first, due at NOON. arrival
order and deadline order are different orders. every queue
system rediscovers this; bakers knew it already. the queue is
the product - choose its discipline like you chose the recipes.
source
# frozen_string_literal: true # The Bakery Rush: two ovens, thirteen orders, one queue - and the # morning is decided before the first tray goes in, by ENQUEUE # ORDER. A bakery is a queue wearing an apron: the plan is the # queue, the concurrency limit is the ovens, and the discipline # (who bakes first) is policy you choose, not fate. We run the same # morning twice - first-come-first-served with the wedding cake up # front, then shortest-bake-first - and measure customer sadness. # Queue theory has opinions about croissants. They are correct. # # bundle exec ruby examples/bakery_rush.rb # # Runs offline; exits 1 unless the discipline change rescues every # croissant customer without making the cake late. require class="s">"bundler/setup" require class="s">"agentic" Agentic.logger.level = class="y">:fatal def mono = Process.clock_gettime(Process:class="y">:CLOCK_MONOTONIC) # The 6am board: everyone "arrived" at open; patience varies wildly ORDERS = [ {item: class="s">"wedding cake", bake: 0.20, patience: 1.00}, # due at noon; the baker's pride {item: class="s">"birthday cake", bake: 0.18, patience: 1.00}, # due at three; has sprinkles *6.times.map { |i| {item: class="s">"croissant ##{i + 1}", bake: 0.02, patience: 0.15} }, *3.times.map { |i| {item: class="s">"baguette ##{i + 1}", bake: 0.04, patience: 0.30} }, *2.times.map { |i| {item: class="s">"eclair ##{i + 1}", bake: 0.03, patience: 0.30} } ].freeze def open_the_doors(orders_in_queue_order) orchestrator = Agentic:class="y">:PlanOrchestrator.new(concurrency_limit: 2) # two ovens, no negotiating opened = mono tickets = {} orders_in_queue_order.each do |order| task = Agentic:class="y">:Task.new(description: order[class="y">:item], agent_spec: {class="s">"name" => order[class="y">:item], class="s">"instructions" => class="s">"bake"}) orchestrator.add_task(task, agent: ->(_t) { waited = mono - opened sleep(order[class="y">:bake]) # the oven does not care about your feelings tickets[order[class="y">:item]] = {waited: waited, done: mono - opened, patience: order[class="y">:patience]} class="y">:golden_brown }) end orchestrator.execute_plan tickets end def morning_report(label, tickets) lost = tickets.select { |_, t| t[class="y">:waited] > t[class="y">:patience] } cakes = tickets.select { |item, _| item.include?(class="s">"cake") }.values mean_wait = tickets.values.sum { |t| t[class="y">:waited] } / tickets.size puts class="s">" #{label}:" puts class="s">" mean wait #{(mean_wait * 1000).round}ms; customers lost to the cafe next door: #{lost.size}" lost.each { |item, t| puts class="s">" walked out: #{item} (waited #{(t[class="y">:waited] * 1000).round}ms, patience #{(t[class="y">:patience] * 1000).round}ms)" } cakes_ok = cakes.all? { |c| c[class="y">:done] <= c[class="y">:patience] } puts class="s">" cakes: done at #{cakes.map { |c| "#{(c[class="y">:done] * 1000).round}msclass="s">" }.join(" and class="s">")} #{cakes_ok ? "- both on timeclass="s">" : "- LATE, catastropheclass="s">"}" [mean_wait, lost.size, cakes_ok] end puts class="s">"THE BAKERY RUSH (a bakery is a queue wearing an apron)" puts fifo = open_the_doors(ORDERS) # cake first: it was ordered first, seems fair fifo_mean, fifo_lost, fifo_cake_ok = morning_report(class="s">"monday, first-come-first-served (two cakes hog BOTH ovens at 6am)", fifo) puts sjf = open_the_doors(ORDERS.sort_by { |o| o[class="y">:bake] }) # shortest bake first; cake waits, but its deadline is NOON sjf_mean, sjf_lost, sjf_cake_ok = morning_report(class="s">"tuesday, shortest-bake-first (same ovens, same orders, new discipline)", sjf) puts puts class="s">" nothing about the bakery changed overnight - not the ovens, not" puts class="s">" the orders, not the bake times. only the DISCIPLINE: monday" puts class="s">" baked in arrival order and the wedding cake sat in an oven for" puts class="s">" 200ms while croissant customers (patience: 150ms) studied the" puts class="s">" cafe across the street. tuesday baked shortest-first, because" puts class="s">" shortest-job-first provably minimizes mean wait - and the cake" puts class="s">" was never actually urgent: ordered first, due at NOON. arrival" puts class="s">" order and deadline order are different orders. every queue" puts class="s">" system rediscovers this; bakers knew it already. the queue is" puts class="s">" the product - choose its discipline like you chose the recipes." exit((sjf_lost.zero? && fifo_lost.positive? && sjf_cake_ok && fifo_cake_ok && sjf_mean < fifo_mean) ? 0 : 1)