Dynamic DES
Realistic event streams from a simulation you can steer while it runs.
Most test data generators write random rows. Dynamic DES writes the events of a working process: orders queue for packers, packing slows down at busy times, and a backlog builds when arrivals outpace capacity. The data has the cause and effect of a real system, because it comes from a SimPy discrete-event simulation.
Change an arrival rate or a capacity while the simulation runs, from Kafka, Redis, PostgreSQL or a timed scenario, and the pipeline downstream sees the effect. One run can write a week of history at full speed, then keep streaming in real time.
Events and telemetry go to Kafka, Redis, PostgreSQL, Parquet or JSONL files (on local disk or S3-compatible storage), or Apache Iceberg tables. A model is a YAML file, a Python builder, or SimPy code.
Used for: testing streaming pipelines with data that behaves like production, demos and workshops, digital twins that follow live data, and training data for models that predict delays or load.
The control dashboard changes simulation parameters while a run is going, and the telemetry reacts without a restart:
Key Features
- Real time or full speed:
DynamicRealtimeEnvironmentruns SimPy in step with the system clock, or unpaced, and reports how far the simulation lags behind real time. - Live parameters: arrival rates, service times and capacities change mid-run through registry paths such as
Shop.arrival.standard.rate. A resource grows at once, and shrinks only as busy units are released, so no work in progress is lost. - Several sinks per run: each sink added with
add_egresshas its ownwhenfilter,batch_sizeandflush_interval, so one run can feed a stream and a data lake together. - Backfill then go live: one run generates backdated history at full speed, then switches to real time at
go_live_at. - Three ways to write a simulation: the low-level
DynamicRealtimeEnvironment, theSimulationContextbuilder, or a YAML blueprint run withddes run. - Serialisation: JSON through
orjsonby default, Avro through the Confluent or AWS Glue Schema Registry for chosen topics, and Pydantic models published as they are. - Kafka security: extra keyword arguments go to the Kafka client, so SASL, mTLS, OAuth and AWS IAM clusters work.
Installation
Install the core library with uv or pip.
With uv:
# The ddes command
uv tool install dynamic-des
# Or the library, in a uv project
uv add dynamic-des
With pip:
pip install dynamic-des
The connectors are optional extras, for example uv add "dynamic-des[kafka,parquet]" or pip install "dynamic-des[kafka,parquet]":
| Extra | Adds |
|---|---|
kafka |
Kafka ingress and egress |
confluent |
Avro with the Confluent Schema Registry (includes kafka) |
glue |
Avro with the AWS Glue Schema Registry (includes kafka) |
redis |
Redis ingress and egress |
postgres |
PostgreSQL ingress and egress |
parquet |
Parquet and JSONL files on local disk or S3-compatible storage |
iceberg |
Apache Iceberg tables through a REST catalog |
all |
Every extra above |
Run an Example
Every example is written three ways: as a YAML blueprint, with the builder API and with the low-level API. The local example needs no container. Here is its YAML version:
ddes examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
With uv
# 1. Install
uv tool install dynamic-des
# 2. Download the example
ddes examples get local --api yaml
cd local/yaml
# 3. Run it
ddes run local.yaml
With pip
# 1. Install
pip install dynamic-des
# 2. Download the example
ddes examples get local --api yaml
cd local/yaml
# 3. Run it
ddes run local.yaml
For the builder or low-level version, use --api builder or --api low-level; the Installation page shows all three in tabs. ddes examples lists the other examples, and each example page gives the same steps, including the odctl service it needs.
Three Ways to Write a Simulation
A simulation can be a YAML blueprint, a script using the builder API (SimulationContext), or a script using the low-level API (DynamicRealtimeEnvironment and SimPy processes). All three build the same parameters and run on the same environment, so the registry paths, the records and the connectors are the same whichever way you choose.
This blueprint is a small online shop: one packer, an order about every 2 seconds and 1.5 seconds of packing, with every record printed to the terminal:
# The First Simulation tutorial: the shop as a blueprint.
# Run it with: ddes run first_shop.yaml
simulation:
sim_id: Shop
factor: 1.0 # 1 simulated second takes 1 real second
resources:
packers: {current_cap: 1, max_cap: 1}
services:
# With no std, a normal distribution returns its mean every time
packing: {dist: normal, mean: 1.5}
arrivals:
# One order every 2 seconds on average; each arrival spawns pack_order
orders: {dist: exponential, rate: 0.5, spawn: pack_order}
tasks:
pack_order:
service: packing
resource: packers
# The finished event's value; id_field adds the task id as order_id
payload: {}
id_field: order_id
egress:
- type: Console
run:
until: 10
First Simulation builds this shop step by step, with the YAML, builder and low-level code side by side at each step, and the comparison of the three ways explains which to choose.
Roadmap
- Planned for 1.0: routing between tasks, entity state, more distributions, stores and containers, built-in statistics and
ddes explain; a simulation server (ddes serve) with a REST API, a browser UI and schedules, run locally through odctl; a page in the docs for each new building block as it ships. - Future work: breakdowns and schedules, transport on maps, data-driven inputs, experiments and analysis, animation, generated values in YAML, more sinks and delivery faults.
The roadmap page has the details.
Learn More
The documentation is at jaehyeon.me/dynamic-des.
- Getting Started: installation, and First Simulation, which builds one online shop step by step with a tab for YAML, the builder API and the low-level API at each step.
- How Simulation Works: what discrete-event simulation is, what SimPy does and what Dynamic DES adds, the building blocks of a model (arrivals and services, tasks and processes, resources), and queues and capacity.
- Core Architecture: the three ways to write a simulation, each in detail (low-level, builder, YAML), and the runtime: the environment, live parameters, time and pacing, connectors, records and telemetry, and batching and delivery.
- Guides: record routing, Avro and Pydantic, secure Kafka, backfill then go live, changing parameters, writing blueprints, and the custom logic guides: Python in a blueprint, multi-resource handoffs, preemptive breakdowns and dynamic topology.
- Examples: one page per example, with the YAML, builder and low-level versions side by side, starting with the overview.
- API Reference: every public class.
- About: the roadmap.
Related reading
Blog posts about dynamic-des and the projects built on it are tagged dynamic-des on jaehyeon.me.
Projects that use dynamic-des:
- benchtop: hands-on data engineering and machine learning demos that run locally, most of them with data produced by dynamic-des.
- agentic-analytics-system: conversational analytics over an Iceberg lakehouse, with the lakehouse data generated by dynamic-des.
- oml-digital-twin-hotrolling: a streaming digital twin of a steel hot rolling mill, with online machine learning on Kafka and Flink.
License
MIT
Metadata
Release files for dynamic-des 0.19.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dynamic_des-0.19.0.tar.gz | 80.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dynamic_des-0.19.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 178.5 kB
Release files / dynamic_des-0.19.0.tar.gz
| Download URL | dynamic_des-0.19.0.tar.gz |
|---|---|
| Size | 80.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e742d7831bed9611235c1c5f6170b9f89109d9cb1824941f77a7e3630e6b438c
|
|
BLAKE2b-256 checksum How to use checksums |
3b81d46b4feb6452032d8effd394dd853a61cac8ac473dbba96282a693e61b6f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logRelease files / dynamic_des-0.19.0-py3-none-any.whl
| Download URL | dynamic_des-0.19.0-py3-none-any.whl |
|---|---|
| Size | 97.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c43faad37eedcf22a52dadcd58c9299c8a027834953cc2a3ad8eefde8927d25b
|
|
BLAKE2b-256 checksum How to use checksums |
a66b340abde419fa2f4c6ef9ae4692e35005955a70da9927052aee1748d69d68
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency log