scheduled-events-and-queues

Scheduled events (Mendix's cron) and task queues in MDL — the eight repeat variants and the fields each takes, and what a queue does and does not throttle. Use when running a microflow on a schedule,

SKILL.md

GitHub
<!-- skill-index: generated by scripts/skill-index.py; make check-skill-index -->

Find it fast

sed -n '<from>,<to>p' SKILL.md one section rather than reading the file; ./mxcli syntax <topic> answers how do I write this for a fraction of either.

lines section
28-38 When to Use This Skill
39-143 Scheduled Events
144-168 Task Queues
169-178 Common Mistakes
179-270 Binding a Call to a Queue — IN QUEUE
271-285 Placing Them in Folders
286-300 Validation Checklist
301-322 Querying and Linting
323-328 Related
329-332 Scheduled events — Mendix's cron (LIST/DESCRIBE/CREATE [OR MODIFY]/DROP). Repeat: names one of the eight ScheduledEvents$*Schedule variants and only that variant's fields are accepted; a field from another repeat is refused by mxcli check (MDL-SCHED01) and by exec, which call the same function. The document shape is pinned by re-serializing three whole Studio Pro-authored events (Workflow Commons 4.11.0, OIDC SSO 4.6.0, SAML 4.2.1) element by element — modelsdk/gen is wrong about two properties here
333-335 Task queues (LIST/DESCRIBE/CREATE [OR MODIFY]/DROP TASK QUEUE). Config.ParallelismExpression is a string and the sibling int32 Parallelism is not written — matching all four Studio Pro queues in Business Events 3.12.1. Binding a call to a queue is not yet authorable, so `CREATE OR REPLACE
<!-- /skill-index -->

Scheduled Events and Task Queues

When to Use This Skill

Use this skill when the user wants to:

  • Run a microflow on a schedule ("every night at 4", "hourly", "cron", "batch job")
  • Inspect or change an existing scheduled event
  • Limit how many background tasks run at once (a task queue)
  • Run a microflow or Java action call on a queue (IN QUEUE)

These two features are unrelated. A scheduled event does not go through a task queue. Its own concurrency control is OnOverlap.

Scheduled Events

Mendix's cron: run a microflow on a repeating schedule.

mdl 1;
-- Inspect
list scheduled events;
list scheduled events in Ops;
describe scheduled event Ops.NightlyCleanup;   -- re-executable MDL

-- Create
create scheduled event Ops.NightlyCleanup (
  Microflow: Ops.SE_Cleanup,
  Repeat: Daily,
  HourOfDay: 4,
  MinuteOfHour: 0,
  TimeZone: Server,
  Enabled: true
);

drop scheduled event Ops.NightlyCleanup;

Microflow and Repeat are always required. show is a synonym for list.

Pick the Repeat first, then use only its fields

Mendix stores the repeat rule as one of eight types, and they differ in which fields they carry — not just in their values. Naming a field from another repeat is an error, not a no-op:

Error: Repeat Daily does not have Multiplier — it takes HourOfDay, MinuteOfHour
Repeat Fields Means
Minutely Multiplier every N minutes
Hourly Multiplier, MinuteOffset every N hours, at :MM past
Daily HourOfDay, MinuteOfHour every day at HH:MM (no multiplier)
Weekly Weekdays, HourOfDay, MinuteOfHour on the named days at HH:MM
MonthlyByDate Multiplier, MonthOffset, DayOfMonth, HourOfDay, MinuteOfHour the Dth of every N months
MonthlyByWeekday Multiplier, MonthOffset, DaySelector, Weekday, HourOfDay, MinuteOfHour the last Friday of every N months
YearlyByDate Month, DayOfMonth, HourOfDay, MinuteOfHour every 2 January
YearlyByWeekday Month, DaySelector, Weekday, HourOfDay, MinuteOfHour the first Monday of March

Field values:

Field Value
Multiplier 1 or more (defaults to 1)
MinuteOffset 0–59
MonthOffset 0-based: which month of a multi-month cycle fires
HourOfDay / MinuteOfHour 0–23 / 0–59
DayOfMonth / Month 1–31 / 1–12
Weekdays quoted list: 'Monday, Friday' (case-insensitive)
DaySelector First, Second, Third, Fourth, Last
Weekday Sunday … Saturday

Optional on any repeat:

Property Values Default
Enabled true / false false — a new event does not run until you enable it
OnOverlap DelayNext / SkipNext DelayNext
TimeZone UTC / Server UTC
StartDateTime RFC 3339, e.g. '2026-01-01T04:00:00Z' none
Documentation free text none

SkipNext drops a run that would overlap the previous one; DelayNext waits.

More examples

mdl 1;
-- Every two hours, 23 minutes past
create scheduled event Ops.HourlyPing (
  Microflow: Ops.SE_Ping,
  Repeat: Hourly,
  Multiplier: 2,
  MinuteOffset: 23
);

-- Mondays and Fridays at 09:30
create scheduled event Ops.WeeklyReport (
  Microflow: Ops.SE_Report,
  Repeat: Weekly,
  Weekdays: 'Monday, Friday',
  HourOfDay: 9,
  MinuteOfHour: 30
);

-- The last Friday of every third month, 18:00
create scheduled event Ops.QuarterEnd (
  Microflow: Ops.SE_Close,
  Repeat: MonthlyByWeekday,
  Multiplier: 3,
  MonthOffset: 2,
  DaySelector: Last,
  Weekday: Friday,
  HourOfDay: 18
);

Task Queues

A task queue bounds how many queued calls run at once. Binding a call to it is a separate step — see IN QUEUE.

mdl 1;
list task queues;
describe task queue Ops.OrderProcessing;

create task queue Ops.OrderProcessing ( Parallelism: 3, ClusterWide: true );
create task queue Ops.Mail;                     -- defaults: parallelism 1, per-instance

create or modify task queue Ops.OrderProcessing ( Parallelism: '$MyModule.Workers' );
drop task queue Ops.Mail;
Property Meaning Default
Parallelism how many run at once — an expression, not a number 1
ClusterWide true = across the cluster, false = per runtime instance false

Mendix stores parallelism as an expression string, so 3 and '3' are the same thing and an arbitrary expression is legal.

Common Mistakes

Mistake Symptom Fix
Multiplier on a Daily repeat Repeat Daily does not have Multiplier Daily has no multiplier — use HourOfDay/MinuteOfHour, or switch to Hourly
Forgetting Enabled: true The event is in the model but never runs Set Enabled: true (the default is false)
TimeZone: server has the wrong casing — Mendix stores it as "Server" Use the exact spelling: Server, UTC, DelayNext, SkipNext, Last, Friday
HourOfDay: 24 it must be between 0 and 23 Hours are 0–23; midnight is 0
Expecting a queue to throttle a scheduled event Nothing changes They are unrelated — use OnOverlap

Binding a Call to a Queue — IN QUEUE

The queue document only defines the concurrency limit. What actually runs work in the background is the binding on the call activity, and Mendix allows it on exactly two: Call microflow and Call Java action. In MDL that is a trailing in queue clause, in the same position on both — after the argument list, before any on error:

mdl 1;
create or modify microflow Ops.ACT_Enqueue ()
begin
  call microflow Ops.ACT_Process(Order = $Order) in queue Ops.OrderProcessing;
  call java action Ops.RefreshData(Url = $Url)   in queue Ops.OrderProcessing;
end;

describe microflow renders the clause back, so the binding round-trips.

Three traps, verified on mxbuild 11.13.0 (the microflow one on 11.12.0)

A queued microflow must return nothing. A call microflow … in queue … whose target declares returns … fails the build with CE7033 "A microflow used for background execution must have a Microflow return type of 'Nothing'.", reported at the call activity. mxcli check reports it as MDL088 — without a project when the script creates the microflow, and under --references for one already stored. Drop the returns clause (and the return value) from the worker microflow:

mdl 1;
create microflow Ops.ACT_Work ($Note: String)   -- no `returns`
begin
  log info node 'Ops' 'working';
end;

A queued Java action must return Nothing. Anything else fails the build with CE7038 "A Java action used for background execution must have a return type of 'Nothing'." mxcli's default return type for create java action is Boolean, so returns void is required, not optional:

mdl 1;
create java action Ops.RefreshData(Url: string not null) returns void
as $$ return; $$;

The queue must exist. A missing one is CE1613 "The selected task queue … no longer exists", reported against the call activity — it names the activity, not the script, so a typo is expensive to trace from the build log. mxcli check --references resolves the name first and reports it against the statement instead.

That CE1613 is also the proof the binding is real: drop the queue on a project mxcli wrote and the error appears, naming both the queue and the activity.

A Rewrite Must Restate the Queue

create or modify microflow rebuilds the microflow from the statement, so a binding the script does not restate is gone. mxcli refuses rather than drop it:

Error: microflow Ops.ACT_Caller has 1 call(s) bound to a task queue that this
script does not restate (Ops.MyQueue), and rewriting it would silently drop the
binding.

Add in queue Ops.MyQueue to the call and the rewrite goes through. Without the refusal the binding was written back as null and the project then looked healthier than before — mx check stopped reporting CE1613, because the configuration the error was about had been deleted.

One thing is still refused: a retry policy on a queued call (Queues$QueueFixedRetry / Queues$QueueExponentialRetry). MDL has no syntax for it, so a rewrite cannot preserve it — change that microflow in Studio Pro.

When a Java Action Is the Better Tool

The activity property gives queueing and nothing else. The runtime API, reachable from a Java action, gives queueing and retry, and can queue a Java action directly with no wrapper microflow:

Core.userActionCall("Ops.RefreshData")
    .withParams(url)
    .withExponentialRetry(5, Duration.ofSeconds(2), Duration.ofMinutes(2))
    .executeInBackground(ctx, "Ops.OrderProcessing");

Use Core.microflowCall(...) when the unit of work really is a microflow.

Placing Them in Folders

Both take a folder clause on create, straight after the qualified name:

mdl 1;
create scheduled event Ops.SE_Nightly folder 'Private/Scheduled events'
  ( Microflow: Ops.ACT_Nightly, Repeat: Daily, StartDateTime: '2026-01-01T02:00:00Z' );

create task queue Ops.Q_Imports folder 'Private/Queues' ( Parallelism: 3 );

On create or modify the clause moves an existing document; omitting it leaves placement alone. See organize-project.

Validation Checklist

Before presenting a script:

mxcli check script.mdl                       # catches wrong-repeat fields (MDL-SCHED01)
mxcli check script.mdl -p app.mpr --references
  • Every scheduled event has Microflow and Repeat
  • Only that repeat's fields are used
  • Enabled: true if it is meant to run
  • Enum values spelled exactly (Server, DelayNext, Last, Monday)
  • The target microflow exists and takes no parameters

Querying and Linting

Both document types are in the catalog after refresh catalog:

-- Anything that fires more often than once a minute
select QualifiedName, RepeatDescription, Microflow
from CATALOG.SCHEDULED_EVENTS
where Enabled = 1 and IntervalSeconds < 60;

select QualifiedName, Parallelism, ClusterWide from CATALOG.TASK_QUEUES;

A scheduled event counts as a caller of the microflow it runs, so list callers of Ops.SE_Cleanup lists it and the lint rule for orphaned microflows (QUAL004) does not flag it. IntervalSeconds is derived from the schedule, not from the legacy Interval/IntervalType pair Mendix also stores.

Starlark lint rules can iterate both: scheduled_events() yields repeat, interval_seconds, on_overlap, time_zone, enabled, and microflow_name; queues() yields parallelism (a string) and cluster_wide.

Related

  • mxcli syntax scheduled-event, mxcli syntax queue — full syntax reference
  • write-microflows — writing the microflow the event calls
  • project-settings — after-startup / before-shutdown microflows

Scheduled events — Mendix's cron (LIST/DESCRIBE/CREATE [OR MODIFY]/DROP). Repeat: names one of the eight ScheduledEvents$*Schedule variants and only that variant's fields are accepted; a field from another repeat is refused by mxcli check (MDL-SCHED01) and by exec, which call the same function. The document shape is pinned by re-serializing three whole Studio Pro-authored events (Workflow Commons 4.11.0, OIDC SSO 4.6.0, SAML 4.2.1) element by element — modelsdk/gen is wrong about two properties here

the integers are stored as int64 (gen says int32, the #585 mismatch) and StartDateTime is a BSON datetime (gen says string), so both engines share one raw-BSON codec in mdl/scheduledevents. Interval/IntervalType are legacy siblings of Schedule that Studio Pro writes and does not keep in sync — derived on CREATE, carried through untouched on MODIFY. Only the Day and Hour variants have a Studio Pro reference; the other six are metamodel-derived and verified to load. Both are in the catalog (CATALOG.SCHEDULED_EVENTS, CATALOG.TASK_QUEUES) and a scheduled event emits a schedule edge into CATALOG.REFS — without it a microflow run only by a scheduled event was reported as dead by list callers, GRAPH_DEAD_ASSETS and lint rule QUAL004.

Task queues (LIST/DESCRIBE/CREATE [OR MODIFY]/DROP TASK QUEUE). Config.ParallelismExpression is a string and the sibling int32 Parallelism is not written — matching all four Studio Pro queues in Business Events 3.12.1. Binding a call to a queue is not yet authorable, so CREATE OR REPLACE|MODIFY MICROFLOW is refused when the stored microflow has a queued call (guard-don't-drop, ADR-0005)

the rebuild used to write QueueSettings back as null, which made mx check go from CE1613 to 0 errors by deleting the user's configuration