Kafka Digital Twin
This example models a shop packing orders. The simulation reads parameter updates from a Kafka topic and publishes events and telemetry to Kafka topics. Each tab shows the example written one way: as a YAML blueprint, with the builder API, or with the low-level API. Ways to write a simulation compares the three.
With KafkaIngress and KafkaEgress in place of the local connectors, the simulation runs as a separate service. Look for the lifecycle events on sim-events and the packers' readings on sim-telemetry, published every 2 simulation seconds. A JSON parameter update sent to sim-config changes the running simulation, and the readings show the change.
Before You Start
The example needs Docker and the odctl profile kafka-lite, which each Quick Start below starts and stops. Services for the Examples shows how to install odctl.
Steps
Run It
This example builds the simulation of the builder example in the Builder tab from a YAML blueprint, with no Python. The connectors, the parameters, the task and the telemetry are all declared in the file.
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
What It Does
The run keeps going until you stop it. When it starts, KafkaEgress creates sim-events and sim-telemetry if they do not exist. The run then publishes task lifecycle events to sim-events, and the packers' four readings (capacity, in_use, queue_length and utilization) and the task's in_progress to sim-telemetry. It applies parameter updates sent to sim-config.
The dashboard in the Quick Start works with this run unchanged, because it reads the same topics and the same four packer readings.
The blueprint reads the broker address with ${KAFKA_BOOTSTRAP_SERVERS:-127.0.0.1:9092}, so the environment variable KAFKA_BOOTSTRAP_SERVERS overrides it.
This version builds the simulation with the builder API (SimulationContext).
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
The run keeps going until you stop it. It logs one line per order when a packer starts on it. It publishes task lifecycle events to sim-events, and the packers' four readings (capacity, in_use, queue_length and utilization) and the task's in_progress to sim-telemetry.
This version wires the simulation by hand on DynamicRealtimeEnvironment, the low-level API.
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
The run keeps going until you stop it. It logs one line per order when a packer starts on it. It publishes task lifecycle events to sim-events, and the packers' four readings (capacity, in_use, queue_length and utilization) and the task's in_progress to sim-telemetry.
Change a Parameter Live
Step 5 of each Quick Start starts a dashboard at http://localhost:8080. It reads sim-telemetry, and its capacity control sends a new current_cap for the packers to sim-config. KafkaIngress applies the update while the run goes, and the packers' capacity reading on sim-telemetry shows the change. Any producer can send the same update: a JSON message such as {"path": "Shop.resources.packers.current_cap", "value": 3} on sim-config.
Check the Result
The three tabs publish the same records, which a test checks by running each version unpaced. A real run sends the events to sim-events and the telemetry to sim-telemetry. desflow run kafka.yaml --sample 5 --stdout prints the first five events, and the telemetry published between them, as JSON lines instead, unpaced and with no broker:
With one packer, orders-1 starts at once and the next orders wait. At 2 simulation seconds the readings show 1 packer in use, 2 orders in the queue and 3 tasks in progress.
Full Files
Full files
The blueprint wires both Kafka connectors and declares the packers, the packing service, the order arrival and the task. The finished event of each task is the fixed payload. stats: minimal publishes the packers' four built-in readings and the task's in_progress every 2 simulation seconds. with_stats("minimal", interval=2.0) does the same in the builder version, and env.setup_stats in the low-level version.
Files live in the examples/yaml/ folder of the repository, and the label on each block below is its path there.
This script connects the simulation to Kafka topics and uses Pydantic models to fix the fields and types of the events.
Scripts live in the examples/ folder of the repository, and the label on the block below is this one's path there.
| examples/builder/kafka_example.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 | |
This script connects the simulation to Kafka topics and uses Pydantic models to fix the fields and types of the events.
Scripts live in the examples/ folder of the repository, and the label on the block below is this one's path there.
| examples/low-level/kafka_example.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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | |