Skip to main content

Overview

A Schedule is what anchors a simulation to real-world timing. Without a schedule, a model runs in abstract time with synthetic arrivals — useful for exploratory work, but not for comparing against your actual floor. With a schedule, the simulation is anchored to real dates, real shift patterns, and real production plans. Material enters when your plan says it does, shift transitions fire at specific wall-clock times, and results are comparable directly to what your floor produced. Every serious use of ProDex involves at least one schedule. Most models have several — one for the “normal” plan, a few for alternative scenarios you’re comparing. Schedules live alongside Snapshots as the two things an Experiment comparison row pulls together. A Snapshot freezes the model + schedule together (the schedule is embedded in the snapshot, not referenced); the schedule active when the snapshot was captured travels with it.

Choosing a Schedule

The schedule selector lives in the Modeler’s top bar. The dropdown lists every schedule defined on the model, plus:
  • Default (no schedule) — when selected, the model runs in abstract time with whatever stochastic arrivals the Sources define. There’s no schedule object behind this — it’s a null selection.
  • + New schedule — creates a fresh, empty schedule and switches to it.
  • Edit — opens the Schedule Editor modal for the currently selected schedule. Lives inside the dropdown menu (not next to the selector).
  • Delete — removes the currently selected schedule. Opens a confirmation dialog: “Delete Schedule — Are you sure you want to delete ‘{name}’? This action cannot be undone.”

The Schedule Editor

The Schedule Editor is a modal titled Edit {schedule name} that takes over the working area while you author a schedule’s timing and events. The top of the modal has four fields that define the schedule:
  • Name — short, descriptive. This is what shows in the top-bar selector.
  • Description — optional free text explaining what this schedule represents.
  • Start Time — the wall-clock moment simulation begins. Every event timestamp on this schedule must fall at or after Start Time.
  • End Time — the wall-clock moment simulation ends. If left blank, the simulation runs for the model’s configured Duration starting from Start Time. If set, End Time overrides Duration.
Datetimes must be timezone-aware. All timestamps on a schedule (Start Time, End Time, and every event’s release_time) must include a UTC offset or Z suffix. Naive datetimes fail validation immediately — the schedule won’t save, and any run against it aborts. The modal datetime picker emits offset-aware values by default; the validator rejects anything else.
Below the four fields, a Timeline / Table view toggle controls how events are presented. Timeline view lays events along a wall-clock axis — handy for spotting shift boundaries and spacing visually. Table view lists every event in a sortable grid — handy for bulk review and spotting timestamp typos. Schema-wise, a schedule contains exactly two top-level arrays:
  • material_releases[] — entities entering the model at specific times
  • scheduled_actions[] — assignments and emissions fired at specific times, optionally gated by a condition
The UI surfaces these as three sections — MATERIAL RELEASE, ASSIGN VARIABLE, EMIT EVENT — because each scheduled action carries an inner actions[] array where each action is either an assign or an emit. The two action types share a parent scheduled_actions[] entry and inherit its release_time and optional condition. A single + button in the modal’s top-right opens a picker for which kind of event to add — material release, assign-variable, or emit-event.

What a Schedule Contains

A schedule is a sequence of material releases and scheduled actions, each stamped with a specific absolute wall-clock time. The simulation runs from Start Time to End Time (or for the model’s configured Duration if End Time isn’t set), and each event fires when wall-clock simulation time reaches its timestamp. Every event timestamp is absolute — not a relative offset from Start Time.

Material Releases

A material release tells a Source or Buffer to emit one or more entities at a specific wall-clock time. The form has these schema fields:
  • element_id — the id of a Source or Buffer to release from. Supports hierarchical addressing (model_node_1::source_1) for components inside a Model Node.
  • entity_type_id — the slug of the entity type to release.
  • quantity — a positive integer (exclusiveMinimum: 0, integer-typed; no DSL union).
  • release_time — absolute wall-clock moment the release fires (timezone-aware ISO datetime).
  • attributes — values to set on the newly created entities using the six assignment strategies: Fixed, DSL Expression, Round Robin, Random Choice, Random, Weighted.
Material releases are how you model “demand that actually happened.” Instead of a Source with a synthetic exponential arrival rate, you give it a sequence of real orders: at Nov 1, 2024 7:00 AM UTC release 50 units of Product A with priority="rush" and due_priority=5; at Nov 1, 2024 9:00 AM UTC release 30 units of Product B; and so on.
A Source’s arrival logic and material releases run in parallel. They aren’t mutually exclusive. A Source can keep producing stochastic arrivals while a schedule simultaneously injects specific batches at scheduled times, and event-driven release_entity actions can fire on top of both. If you want a schedule-only Source, leave its arrival logic empty.

Scheduled Actions

A scheduled action fires at a specific wall-clock time without being tied to any component’s lifecycle event. Schema fields:
  • release_time — absolute wall-clock moment the action fires (timezone-aware).
  • condition (optional) — boolean DSL expression. The action only fires if the condition evaluates true at release_time.
  • actions[] — list of assign or emit entries that fire together at this time.
The two action types are: Component-bound actions — Pause, Resume, Set Capacity, Release Entity — are not valid as scheduled actions directly. If you need a scheduled capacity change, the pattern is:
  1. A scheduled emit fires at the shift boundary — for example, publish topic shift_start_night.
  2. An Event Listener on the resource subscribes to that topic and sets capacity to the night value.
This separation keeps schedules declarative (“at Nov 1, 2024 6:00 PM UTC, announce that the night shift has started”) and lets Event Listeners handle the component-level side effects.
SELF is not available in scheduled actions. SELF is restricted to event hooks and event listeners. From a scheduled action, reference components by their explicit id in component query functions instead.

Hierarchical Addressing

element_id accepts the :: separator for components inside a Model Node. Examples:
  • source_1 — a top-level Source
  • model_node_1::source_1 — a Source inside a Model Node
  • outer_node::inner_node::buffer_1 — deeply nested
All segments are component slugs, not display names. The :: separator is reserved — no single component id may contain it.

The Shift Scheduling Pattern

Most factories have shift-based capacity that changes through the day and week. The idiomatic way to model this in ProDex combines schedules, topics, state variables, and event listeners:
  1. A shift state variableCURRENT_SHIFT, type text, initial value "day".
  2. Scheduled emit actions at shift boundaries — publish topic shift_day at each day-shift start, publish topic shift_night at each night-shift start, each stamped with its specific wall-clock release_time.
  3. An Event Listener on each affected resource subscribing to the shift topics — when shift_night is published, set CNC machine capacity to the night value and update CURRENT_SHIFT to "night".
  4. Expressions reference CURRENT_SHIFT — arrival rates, priority scoring, and anything else that varies by shift reads the state variable and branches accordingly.
This decomposition keeps the shift logic in one place (the Event Listener on the resource) and the shift timing in the schedule. Swap the schedule for a different shift plan and the capacity changes flow through automatically.

Multiple Schedules per Model

A model can have multiple schedules defined simultaneously. Each is a complete set of material releases and scheduled actions with its own Start Time and End Time; you pick which one to use from the top-bar selector when running a simulation, and any Snapshot saved while a schedule is active embeds that schedule for downstream runs. Typical uses:
  • Baseline vs. stress scenarios — a “normal” schedule and a “demand surge” schedule, compared in the same experiment.
  • Historical replay — last month’s actual demand as one schedule, a planned demand forecast as another.
  • Shift variations — a standard five-day schedule and an alternative seven-day weekend-coverage schedule.
An Experiment row pairs a Snapshot (model + schedule, embedded) with another. Varying the schedule across snapshots lets you ask “how does this model configuration perform under different demand profiles?” Varying the model lets you ask “which configuration is best for this demand?”

Start Time and End Time

  • Start Time is the wall-clock moment simulation begins. Every material release and scheduled action timestamp must fall at or after Start Time.
  • End Time, if provided, is when simulation ends. Useful for running the same schedule against a shorter or longer window without editing the schedule’s events.
  • If End Time is left blank, the simulation runs for the model’s configured Duration from Start Time.
  • Events timestamped after End Time (or after Start Time + Duration if no End Time is set) never fire.
Time zones matter — the same schedule run with Start Time in UTC vs. local time will produce different results for shift boundaries unless the shift events are stamped in the same zone. The Schedule Editor displays times in your selected zone; pick one and stick with it for the whole schedule.

Tips

  • Every serious model needs a schedule. Synthetic arrivals are fine for the first pass; real schedules are required for comparable results.
  • Use absolute wall-clock timestamps consistently. It’s tempting to think in relative offsets (“release at +3600s”) but every event needs an absolute release_time. If you’re sketching out a schedule on paper, compute the absolute timestamps from your base Start Time before entering them.
  • Use condition on scheduled actions to gate behavior on runtime state — e.g., only emit a topic if a state variable is in a particular mode.
  • Keep schedule-level logic in the schedule, component-level logic in Event Listeners. The schedule emits the signal; the listener handles the side effects.
  • Use multiple schedules for experiments. The whole point of experiments is comparison — schedules are one axis of variation, model configuration the other.
  • Two events at the same timestamp fire in an unspecified order. If ordering matters, stagger them by a small amount (a second) or chain them through a topic.