Skip to content

2.27.0

Choose a tag to compare

@rmcdaniel rmcdaniel released this 13 Nov 01:43
6a0aa6f
  • 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 and workflow: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, RunTimerTask and RunServiceCall jobs now act only on
    the new workflows.v2.namespaces allowlist (DW_V2_NAMESPACES). Unset, it
    is exactly workflows.v2.namespace, so a single-namespace app behaves as
    before. A comma-separated list serves each listed namespace (default is
    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 separate workflows.v2.all_namespaces (DW_V2_ALL_NAMESPACES)
    opt-in. Upgrade note: an embedded app that starts, schedules or signals
    workflows in namespaces other than DW_V2_NAMESPACE must 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 set DW_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 new namespace_scope_refusals block
    with the app's allowlist and refusals per namespace and path over the last
    15 minutes: job counts each skipped queued job, and repair, timeout
    and schedule_tick count 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 advisory namespace_scope_refusals health 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.