-
Closing a child no longer reads every sibling's history under the parent
lock (#892). Before, each child close loaded the full history of every
other child of its parent to record the outcome, check a parallel group
and re-project the parent, so a wide fan-out did quadratic history reads
while blocking the parent's own workflow task. Now a close reads the
closing child's history and the parent's own history and links. A
sibling's outcome comes from the parent's resolution event, or from the
sibling's terminal event when none is recorded yet. Measured with 50
children, closing all of them read 96,052 sibling history rows on the
embedded path and 26,460 through the service-mode bridge for a parallel
group; both now read none, and history queries per close no longer grow
with the number of children. Outcomes, wake-ups and projections are
unchanged. -
A child close now costs the parent the same number of queries however many
siblings it has (#892). The parent re-projection reuses the child runs it
batch-loads with its child links instead of fetching each sibling again for
every wait, lineage and summary lookup, and it reads the parent's lineage
rows in one query. Embedded, queries per close went from 218, 372 and 790
at 2, 10 and 30 children to 172, 158 and 156. Through the service-mode
bridge (parallel group) they went from 153, 333 and 755 to 130, 141 and 143.
The close that completes a parallel group still records every member's
resolution once. Projections are unchanged. -
Embedded task repair and execution now stay inside the app's namespaces
(#889). Before, apps sharing one database with the same connection and
queue names could repair, redispatch, time out and run each other's tasks
with the wrong app's code and credentials. The watchdog (including the
queue worker's wake andworkflow:v2:repair-pass), existing and missing
task repair, run deadlines, activity timeouts, service-call deadline,
dispatch and linked-call repair,workflow:v2:schedule-tick, and the
RunWorkflowTask,
RunActivityTask,RunTimerTaskandRunServiceCalljobs now act only on
the newworkflows.v2.namespacesallowlist (DW_V2_NAMESPACES). Unset, it
is exactlyworkflows.v2.namespace, so a single-namespace app behaves as
before. A comma-separated list serves each listed namespace (defaultis
the unscoped one); an empty value serves none;*is refused. A queued
job outside the allowlist, including one queued before upgrading, is
skipped before any effect and logged as a warning. Serving every namespace
needs the separateworkflows.v2.all_namespaces(DW_V2_ALL_NAMESPACES)
opt-in. Upgrade note: an embedded app that starts, schedules or signals
workflows in namespaces other thanDW_V2_NAMESPACEmust list them in
DW_V2_NAMESPACES, or their tasks and schedules wait for an app that
serves them. A process that repairs or ticks every namespace, such as the
standalone server, must setDW_V2_ALL_NAMESPACES=true. The allowlist is an
execution-safety boundary, so one app never runs another app's work with the
wrong code or credentials. It is not tenant isolation: apps that share one
database can still read each other's rows. -
Work refused by the namespace allowlist is now counted, so a misconfigured
upgrade no longer stalls tasks with a log line as the only sign (#1112).
The operator metrics snapshot has a newnamespace_scope_refusalsblock
with the app's allowlist and refusals per namespace and path over the last
15 minutes:jobcounts each skipped queued job, andrepair,timeout
andschedule_tickcount repair candidates, expired activity and run
deadlines, and due schedules that a pass left in a namespace outside the
allowlist after they had waited more than two minutes (sampled at most once
a minute per path). The new advisorynamespace_scope_refusalshealth check
warns while refusals keep arriving and clears 15 minutes after the last one.
The skipped-job warning is now logged once per namespace a minute; the rest
are counted. Counts live in the default cache store in one-minute buckets,
with no table and no migration. Use a shared store (Redis, database or
Memcached) so the web process that serves the health snapshot sees the
workers' counts.
Upgrade: no migration. If an embedded app starts, schedules or signals workflows in namespaces other than DW_V2_NAMESPACE, list them in DW_V2_NAMESPACES. A process that repairs or ticks every namespace sets DW_V2_ALL_NAMESPACES=true.