GenStage in the Kitchen

GenStage in the Kitchen

Slides for Elixir.LDN 2016 talk.

Abstract:

GenStage is the Elixir core team’s effort to provide a set of flexible, composable primitives for concurrent, demand-driven event processing.

Our use case is a restaurant simulation, with tables placing orders, a waiter, a chef and line cooks ready to prepare amazing dishes.
We’ll map GenStage’s core concepts to constraints in our restaurant simulation and see how our system copes by stressing its different components, isolating some useful principles along the way.

8f29619526ac4fb3d9b78c82eaa5e40e?s=128

Claudio Ortolina

September 22, 2016
Tweet

Transcript

  1. www.erlang-solutions.com GEN STAGE IN THE KITCHEN

  2. www.erlang-solutions.com HELLO! Claudio Ortolina claudio.ortolina@erlang-solutions.com www.erlang-solutions.com @cloud8421

  3. www.erlang-solutions.com “ What would you like to be if you

    weren't a software developer?
  4. www.erlang-solutions.com A CHEF Trying to, at least

  5. www.erlang-solutions.com MEET MASSIMO BOTTURA. HE RUNS OSTERIA FRANCESCANA, THE BEST

    RESTAURANT IN THE WORLD
  6. www.erlang-solutions.com NEXT BEST THING GEN STAGE TO MODEL A RESTAURANT*

    * Simplified version
  7. www.erlang-solutions.com 1. GEN STAGE PRIMER

  8. www.erlang-solutions.com TRADITIONAL EVENT DRIVEN FLOW PRODUCER PRODUCER/CONSUMER CONSUMER PUSH 10

    PUSH 10 QUEUE ALL GOOD HERE
  9. www.erlang-solutions.com DEMAND DRIVEN FLOW PRODUCER PRODUCER/CONSUMER CONSUMER ASK 10 ASK

    10 ALL GOOD HERE QUEUE/FAILS
  10. www.erlang-solutions.com MIN_DEMAND AND MAX_DEMAND PRODUCER CONSUMER (MIN 3, MAX 5)

    ASK 2 ASK 5 PROCESS 3 ASK 2 PROCESS 3
  11. www.erlang-solutions.com PROCESS WHILE REQUESTING No one stays idle

  12. www.erlang-solutions.com TABLE 1 TABLE 2 TABLE 3 TABLE 4 WAITER

    CHEF LINE COOK (GRILL) LINE COOK (OVEN) ... ...
  13. www.erlang-solutions.com TABLES ▸ People take some time to choose a

    dish from the menu ▸ When everyone has decided, they call the waiter; they get upset and leave if the waiter doesn't reply in 5 seconds ▸ After ordering, they wait until 30 seconds for the first dish to be delivered. When they receive it, they can wait another 30 seconds. ▸ If dishes aren't delivered on time, they will leave.
  14. www.erlang-solutions.com WAITER ▸ Collects orders from tables ▸ Delivers orders

    to the chef ▸ When dishes are ready, delivers them to the appropriate table
  15. www.erlang-solutions.com CHEF ▸ Receives orders ▸ Distributes dishes to each

    line cook
  16. www.erlang-solutions.com LINE COOK ▸ Receives a dish request ▸ Prepares

    dish and informs the waiter so that it can be picked up
  17. www.erlang-solutions.com TABLE 1 TABLE 2 TABLE 3 TABLE 4 WAITER

    CHEF LINE COOK (MEAT) LINE COOK (OVEN) ... ... PLACE ORDERS DEMANDS ORDERS DEMAND DISHES
  18. www.erlang-solutions.com TABLE WAITER CHEF LINE COOK LINE COOK TABLE Icons

    Designed by Freepik and distributed by Flaticon GenStage
  19. www.erlang-solutions.com TABLE WAITER CHEF LINE COOK LINE COOK TABLE Icons

    Designed by Freepik and distributed by Flaticon PRODUCER BROADCAST DISPATCHER GenStage
  20. www.erlang-solutions.com TABLE WAITER CHEF LINE COOK LINE COOK TABLE Icons

    Designed by Freepik and distributed by Flaticon PRODUCER/CONSUMER PARTITION DISPATCHER GenStage
  21. www.erlang-solutions.com TABLE WAITER CHEF LINE COOK LINE COOK TABLE Icons

    Designed by Freepik and distributed by Flaticon CONSUMER PARTITION CONSUMER PARTITION GenStage
  22. www.erlang-solutions.com TABLES - LOOK AT THE MENU defmodule Osteria.Table do

    use GenServer def init([number, size]) do … send(self(), :look_at_menu) … end def handle_info(:look_at_menu, state) do schedule_decide() {:noreply, state} end end
  23. www.erlang-solutions.com TABLES - DECIDING DISHES defp schedule_decide do time =

    Enum.random(50..500) Process.send_after(self(), :decide, time) end def handle_info(:decide, state = %__MODULE__{number: number, size: size, dishes: dishes}) do case length(dishes) do ^size -> inform_waiter(number, dishes) {:noreply, %{state | phase: :waiting}, waiting_time()} _ -> schedule_decide() {:noreply, %{state | dishes: [random_dish() | dishes]}} end end
  24. www.erlang-solutions.com TABLE WAITER GenStage.reply ORDER GenStage.call ...

  25. www.erlang-solutions.com INFORMING A WAITER REQUIRES A REPLY You do wanna

    know if they got your order
  26. www.erlang-solutions.com ORDER ORDER ORDER :queue.in :queue.out TABLE 1 CHEF WAITER

    (DISPATCHER)
  27. www.erlang-solutions.com WAITER handle_demand/2 GenStage.async_subscribe CHEF handle_events/3 ORDER

  28. www.erlang-solutions.com CHEF LINE COOK handle_demand/2 GenStage.async_subscribe handle_events/3 DISH

  29. www.erlang-solutions.com LINE COOK handle_cast/2 GenStage.cast handle_cast/2 WAITER TABLE 1 GenServer.cast

    DISH DISH ...
  30. www.erlang-solutions.com DEMAND IS DRIVEN BY LINE COOKS The faster they

    cook, the faster food can be served at the table
  31. www.erlang-solutions.com DEMO TIME

  32. www.erlang-solutions.com THANK YOU! Any questions? claudio.ortolina@erlang-solutions.com www.erlang-solutions.com @cloud8421