Skip to content

Native: enforce the structural limits published PHP Server enforces #612

Closed

Description

@rmcdaniel

Part of #325.

For deployments whose workflows run on external workers, published PHP Server enforces these Workflow package structural limits, configured by DW_V2_LIMIT_* (legacy WORKFLOW_V2_LIMIT_*):

Limit Default Where PHP applies it
memo_size_bytes 262144 memo upserts
command_batch_size 1000 upper bound on a command's parallel_group_size metadata
pending_signal_count 5000 signal intake
pending_update_count 500 update intake
payload_size_bytes 2097152 signal and update arguments, and an activity's successful result

The native server enforces only memo_size_bytes. A deployment that relies on one of the others, at its default or a configured value, gets no refusal from native where PHP refuses.

The other package limits (pending activities, children and timers, history transaction size, search attribute size) are checked only on PHP's in-process execution path, which external workers do not reach. See the evidence in the first comment.

Goal

For the same request and configuration, native refuses exactly where published PHP Server refuses, with PHP's status, reason and limit metadata. The run's state after a refusal matches PHP's.

Acceptance

  • Native reads each applicable DW_V2_LIMIT_* setting with PHP's precedence and casts, and a zero or negative value behaves as in PHP.
  • Differential tests against published PHP cover each enforced limit at, below and above its boundary on SQLite, MySQL/MariaDB and PostgreSQL.
  • Report update intake limits as structural_limit_exceeded in service mode #506's corrected reason is followed once it ships.

Activity

  1. rmcdaniel commented on Oct 21, 2026

    @rmcdaniel
    MemberAuthor

    Scope from reading the published 2.5.14 image (ghcr.io/durable-workflow/server@sha256:28fa0f39…), Workflow package vendor/durable-workflow/workflow/src/V2:

    Enforced for external-worker deployments

    • memo_size_bytes: DefaultWorkflowTaskBridge (memo upserts). Native already enforces it.
    • command_batch_size: only as the upper bound on a command's parallel_group_size metadata (DefaultWorkflowTaskBridge::parallelMetadataEntry, WorkflowCommandNormalizer::parallelMetadataEntry). Larger metadata is treated as invalid parallel metadata.
    • pending_signal_count and payload_size_bytes at signal intake: WorkflowStub signal paths (guardPendingSignals) and recordAcceptedSignal (guardPayloadSize).
    • pending_update_count and payload_size_bytes at update intake: app/Support/ExternalWorkflowUpdateAdmission. Its refusal reason is the subject of Report update intake limits as structural_limit_exceeded in service mode #506.
    • payload_size_bytes on an activity's successful result: ActivityOutcomeRecorder.

    Not reached by external-worker commands

    pending_activity_count, pending_child_count, pending_timer_count, history_transaction_size and search_attribute_size_bytes, along with the payload size of scheduled activity or child arguments, continue-as-new arguments and workflow output, are checked only in WorkflowExecutor and the local-activity paths. Those run PHP workflow code in-process. DefaultWorkflowTaskBridge::applyScheduleActivity and the other worker command handlers do not call them.

    So the native work is the four enforced items above, not all ten limits. Each still needs a differential check against published PHP, for the refusal shape and the run's state afterwards.

  2. rmcdaniel commented on Nov 4, 2026

    @rmcdaniel
    MemberAuthor

    Server open-item pass, 2026-11-04.

    Owner: Server for native limit parity; Workflow owns canonical embedded units. The opening memo-only status is stale as a source inventory: current native memo_limits/activity paths include pending signal/update counts and payload checks, while operator metrics expose several configured limits. Presence of those functions is not complete configured-boundary/artifact qualification.

    Next is a per-limit table binding environment precedence, zero/negative behavior, unit, admission site, typed reason and real backend differential fixture. In particular, distinguish parallel metadata's fixed1000 bound from an honored configurable command limit and separate external-worker boundaries from in-process-only Core guards. General/Workflow: review any intentional divergence with central #228 before a new producer/setting is advertised. No boundary exception was removed here.

  3. rmcdaniel commented on Nov 4, 2026

    @rmcdaniel
    MemberAuthor

    Core limit-unit source pointers requested in Server325/6643408164: public 2.20.3 StructuralLimits, StructuralLimitKind, StructuralLimitExceededException, unit boundary controls and feature controls. Retain the distinct pending counts, canonical serialized payload/value sizes, repeated encoded history bytes and logical write work; raw ingress, external blob size and operator totals are separate units. The accepted forward decisions are Workflow853/6643091946 (fixed hard cap plus tighter configured limit, identical admission carriers) and 930/6643088845 (Phase-B repeated logical work/accounting, bounded admission/cleanup). Those are source decisions, not an already shipped all-setting parity claim. Workflow owns the embedded source draft after #1030; Server owns its native per-setting/status/unit table and shared boundaries. No new resource run.

    Delivery evidence remains the exact public Core 2.20.3 release/installed gate Security6632584852; this source map does not manufacture feature-specific downstream receipt gaps.

  4. rmcdaniel commented on Nov 11, 2026

    @rmcdaniel
    MemberAuthor

    Closing: native enforces the PHP structural limits for signals, updates, activity results and command batches (message_streams.rs, updates.rs, execution.rs, completion_rules.rs). Open a narrow issue if a specific fixture differs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions