How desflow Works
This page shows how desflow is built: the parts that run a model, why each one exists, and how a run moves through them. Each part links to the How It Works section that describes it in full.
What It Is
desflow is built on SimPy. SimPy gives the event list, the clock, processes and resources, and desflow keeps all of them. SimPy leaves seven things to the modeller, and each part of desflow adds one of them:
| Left to the modeller in SimPy | What desflow adds | Read |
|---|---|---|
| the code around a model: a class of parameters, an entity class, a model class and a loop over runs | three ways to write a model, each built on the one below | Ways to Write |
one pacing factor, fixed when the environment is made |
one environment that runs history at full speed, then switches to the wall clock | Time and Pacing |
| random times, drawn by the model's own code | ten checked distributions, each with a random stream of its own | Arrivals and Services |
| parameters that only the model's code changes | a registry of named paths that connectors, scenarios and processes change during a run | Live Parameters |
| resources, stores and containers that keep the capacity they were made with | resources, stores and containers whose capacity follows the registry | Resources |
| output, which the model prints or logs | records of a fixed shape, written to sinks on a thread of their own | Egress |
| statistics, replications and confidence intervals | statistics collected during the run, replications, experiments and explain |
Built-in Statistics |
Coming from SimPy compares each change with plain SimPy.
Look at how one run moves through these parts:

Whichever way a model is written, it builds one environment, and one run goes the same way from there. The environment holds the registry of live parameters, and the resources, stores and containers follow it. Ingress connectors change registry values from outside while the run goes on. Tasks and other processes publish events and telemetry, and egress connectors write them to their sinks on a thread of their own. The registry paths, the records, the batching and the connectors are therefore the same in all three ways.
How It Works
Writing a Model
A YAML blueprint, the builder API and the low-level API are layers, not alternatives. from_yaml reads a blueprint, checks it and makes the calls a Python script would make on the builder, SimulationContext. The builder's run() then takes the steps a low-level script writes by hand: it builds the environment, registers the parameters, builds the resources, stores and containers, and starts the processes. The layers mix: a blueprint calls Python with !python, and a builder process can use the environment directly. YAML Blueprints describes how a file is loaded, and What run() Does lists the steps of run() in order.
Environment and Pacing
DynamicRealtimeEnvironment is SimPy's RealtimeEnvironment with four additions: the registry, the ingress connectors, the egress connectors and the statistics. SimPy's factor cannot change once the environment exists. desflow runs without waiting at factor: 0 and switches to real time at go_live_at, so one run can write a week of history and then stream live. Every record carries a logical date and time from logical_start_time. Time and Pacing describes the switch and the end of a run.
Random Times
Every distribution family is declared once, in one table that YAML, the builder and the registry all read. A Sampler reads a distribution's parameters at each draw, so a change during a run applies from the next draw. Each distribution draws from a random stream of its own, made from the run's seed and the distribution's registry path. Adding a distribution therefore leaves the draws of every other one unchanged. Arrivals and Services describes the streams.
Registry
The registry holds every live value under a dot path, such as Shop.service.packing.mean. Each path holds a DynamicValue: the value, and a signal that fires when the value changes. An update is checked before it is stored. An unknown path is ignored, a value is converted to the path's type, a distribution parameter must pass its range rules, and a capacity is kept within its limits. Live Parameters describes each check.
Resources, Stores and Containers
desflow's resources, stores and containers wait on their registry paths, so their capacity changes during a run. A resource that shrinks lets its busy units finish. A resource grants its units in the same steps as SimPy's Resource, so two events at the same time resolve as they would in plain SimPy. Resources and Stores and Containers describe them.
Threads, Ingress and Egress
A run uses three threads. The SimPy thread runs the model. The ingress thread runs the sources, such as Kafka or PostgreSQL, and each source puts (path, value) pairs on a queue. The egress thread runs the sinks, which write batches of records. Each connector has one method, async run(queue), which runs on its thread's asyncio loop, so a network wait never stalls a simulation step. Time and Pacing shows the threads, Ingress how a change reaches the registry, and Egress how a record reaches a sink. Write a Connector writes one of your own.
Two Kinds of Queue
The word queue means two different things in desflow. Look at the two side by side:

A waiting line in the model holds entities, such as orders waiting for a packer. A resource keeps its line in queue, ordered fifo, lifo or by priority, and a request past its queue_limit raises QueueFull. Stores and containers have lines of puts and gets that wait. These lines are what a study measures: their lengths and waits are in the records and the statistics.
A hand-off queue holds data on its way between threads. The ingress queue has no limit, and the ingress monitor applies what it holds every 0.1 simulation seconds. Each sink has its own queue of at most max_queued_batches batches. When a sink's queue is full, the simulation waits, so a slow sink slows the run instead of building a backlog. When it stays full for drain_stall_seconds, the run stops rather than lose records. These queues change how fast the records arrive, never what they hold.
Measurement and Explain
The environment keeps one statistics object, which collects readings, time-weighted averages, counts, waits and service times while the run goes on. Replications build the model again for each seed, run it without pacing, ingress or egress, and give a Student t interval over the runs. Experiments run replications for each design. desflow explain reads the model's graph before anything runs and applies queueing formulas to it. Built-in Statistics, Replications, Experiments and Command Line describe each.