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. Each Quick Start below starts the profile, and the Check the Result section stops it. 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, and KafkaIngress creates sim-config if it does 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.
Stop the run and the dashboard with Ctrl + C, and leave the service up. This command reads the first three events back from the broker:
It prints three JSON lines, then Processed a total of 3 messages. The first two are orders-1 queued and started, both at sim_ts 1.2761899383482334, and the third is orders-2 queued. Each timestamp is the wall-clock time of your run:
Use --topic sim-telemetry to read the packers' readings, or open the Kafka UI at http://127.0.0.1:8086. A second run appends to the same topics, so start again with an empty broker when you want only one run in them. When you have checked the result, stop the service:
In kafka/yaml, which desflow examples get kafka --api yaml creates, desflow run kafka.yaml --sample 5 --stdout needs no broker. It prints the first five events, and the telemetry published between them, as JSON lines, unpaced:
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 122 123 124 125 126 127 128 129 130 | |
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 170 171 172 173 174 175 176 177 178 179 | |