Scheduled Events and Task Queues
SkillProductivityLets your agent set up scheduled events and task queues in Mendix apps, including the eight repeat variants and queue throttling.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Scheduled Events and Task Queues skill
About this capability
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, or bounding how many background tasks run at once.
What this skill tells your AI
The instructions your AI receives, as published by mendixlabs/mxcli in .claude/skills/mendix/scheduled-events-and-queues/SKILL.md and read by ahel’s review.
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.
-- 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
-- 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.
list queues;
describe queue Ops.OrderProcessing;
create queue Ops.OrderProcessing ( Parallelism: 3, ClusterWide: true );
create queue Ops.Mail; -- defaults: parallelism 1, per-instance
create or modify queue Ops.OrderProcessing ( Parallelism: '$MyModule.Workers' );
drop 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:
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.
Two traps, both verified on mxbuild 11.13.0
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:
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 replace|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:
create scheduled event Ops.SE_Nightly folder 'Private/Scheduled events'
( Microflow: Ops.ACT_Nightly, Repeat: Day, StartDateTime: '2026-01-01T02:00:00Z' );
create 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
MicroflowandRepeat - Only that repeat's fields are used
-
Enabled: trueif 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.QUEUES;
A scheduled event counts as a caller of the microflow it runs, so
show 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 referencewrite-microflows— writing the microflow the event callsproject-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.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 show callers, GRAPH_DEAD_ASSETS and lint rule QUAL004.
Task queues (LIST/DESCRIBE/CREATE [OR MODIFY]/DROP 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
Signals
- GitHub stars
- 122
- Forks
- 49
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
scheduled-events-and-queues- Source
- github.com/mendixlabs/mxcli