Skip to content

CRE Gate and Limit Handling Improvements - #23458

Open
tarcisiozf wants to merge 5 commits into
developfrom
DEVSVCS-5859/fix-early-returns
Open

tarcisiozf wants to merge 5 commits into
developfrom
DEVSVCS-5859/fix-early-returns

Conversation

@tarcisiozf

@tarcisiozf tarcisiozf commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

This pull request introduces several improvements and refactorings related to limit enforcement, monitoring, and dependency management across the codebase. The most significant changes involve replacing the use of the Limit method with the more accurate Open method for gate checks, enhancing metrics to better track limit-related issues, and updating dependencies for improved stability and compatibility.

Limit enforcement and gate checking:

  • Replaced calls to the Limit method with the Open method in gate checks throughout the codebase, ensuring correct semantics for evaluating if a gate is open (e.g., in server_request.go and zone_b_restriction.go).
  • Refactored the Vault OCR plugin to use a new forceEmptyOCRRounds method for gate checks, replacing the previous gateAllows helper and updating all relevant usages.

Monitoring and metrics enhancements:

  • Added two new counters to EngineMetrics and corresponding increment methods to track: (1) limit reads that failed and fell back to defaults, and (2) limit checks that went unenforced due to evaluation failures. Also added a new metric label key limitKey for better attribution.

Configuration and limiters:

  • Updated the workflow engine's limiter configuration to use a BoundLimiter[time.Duration] for TriggerEventMaxAge instead of a TimeLimiter for TriggerEventQueueTime, and updated all relevant references for improved clarity and correctness.

@github-actions

Copy link
Copy Markdown
Contributor

✅ No conflicts with other open PRs targeting develop

@github-actions

Copy link
Copy Markdown
Contributor

I see you updated files related to core. Please run make gocs in the root directory to add a changeset as well as in the text include at least one of the following tags:

  • #added For any new functionality added.
  • #breaking_change For any functionality that requires manual action for the node to boot.
  • #bugfix For bug fixes.
  • #changed For any change to the existing functionality.
  • #db_update For any feature that introduces updates to database schema.
  • #deprecation_notice For any upcoming deprecation functionality.
  • #internal For changesets that need to be excluded from the final changelog.
  • #nops For any feature that is NOP facing and needs to be in the official Release Notes for the release.
  • #removed For any functionality/config that is removed.
  • #updated For any functionality that is updated.
  • #wip For any change that is not ready yet and external communication about it should be held off till it is feature complete.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Risk Rating: MEDIUM — changes touch core workflow-engine execution control-flow (early returns, limiter fallbacks, metering lifecycle), which can affect reliability/observability across all runs.

This PR adjusts the workflows v2 engine to fail soft when dynamic limit reads error (use static defaults instead of dropping runs/events), and to surface previously-silent early drops by emitting Started/Finished events plus a new fallback metric.

Changes:

  • Convert several limiter read error paths (trigger queue age, execution timeout, log event cap sizing, execution response size, etc.) from “drop/return” to “fallback to static default + metric”.
  • Add platform_engine_limit_read_fallback_total metric (labeled by limit key) and wire it into the engine paths that now fail-soft.
  • Improve observability for early execution abandonment (e.g., metering reserve failure) by emitting Started/Finished even when returning before the “normal” emit points; add regression tests for these drop paths.

Areas needing scrupulous human review:

  • Engine.startExecution early-return behavior (new emitDroppedExecution helper + metering End() guarded-defer): verify event emission, store state transitions, and metering report lifecycle are correct for every return path (including sharding denials, reserve failures, trigger-index conversion failures, and timeout paths).
  • Limiter fallback defaults: confirm each fallback uses the intended settings key + default value for the specific limiter being read, and that the new fallback metric won’t introduce excessive label cardinality.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
core/services/workflows/v2/engine.go Implements fail-soft limiter reads, adds early-drop Started/Finished emission, and ensures metering reports are ended on early returns.
core/services/workflows/v2/engine_drop_paths_test.go Adds regression tests for limiter read fallbacks and early-drop observability/metering cleanup paths.
core/services/workflows/v2/config.go Tracks effective limiter defaults used to construct EngineLimiters to support correct fallback values.
core/services/workflows/monitoring/trigger_drop_reason.go Documents legacy drop reasons retained for dashboard compatibility (now expected to fall to 0).
core/services/workflows/monitoring/monitoring.go Registers and emits the new limit-read-fallback metric counter.
core/platform/monitoring.go Adds limitKey observability label constant for the new metric.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread core/services/workflows/v2/engine_drop_paths_test.go
Comment thread core/services/workflows/monitoring/monitoring.go
@trunk-io

trunk-io Bot commented Aug 19, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@tarcisiozf
tarcisiozf force-pushed the DEVSVCS-5859/fix-early-returns branch 2 times, most recently from e41d103 to 4b4895b Compare August 19, 2026 17:10
Comment thread core/services/workflows/v2/engine.go
@tarcisiozf
tarcisiozf force-pushed the DEVSVCS-5859/fix-early-returns branch from 4b4895b to 368c962 Compare August 20, 2026 17:34
@tarcisiozf
tarcisiozf requested a lite review from Copilot August 20, 2026 17:34
@tarcisiozf tarcisiozf changed the title fail-soft / early-returns CRE Gate and Limit Handling Improvements Aug 20, 2026
@tarcisiozf
tarcisiozf marked this pull request as ready for review August 20, 2026 17:36
@tarcisiozf
tarcisiozf requested review from a team as code owners August 20, 2026 17:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

Comment thread core/services/workflows/v2/engine.go Outdated
@tarcisiozf
tarcisiozf force-pushed the DEVSVCS-5859/fix-early-returns branch from 1c6988e to f61912b Compare August 24, 2026 20:33
@tarcisiozf
tarcisiozf enabled auto-merge August 24, 2026 20:54
@tarcisiozf
tarcisiozf force-pushed the DEVSVCS-5859/fix-early-returns branch from f61912b to cd0c37a Compare August 25, 2026 13:48
@tarcisiozf
tarcisiozf marked this pull request as draft August 25, 2026 13:53
auto-merge was automatically disabled August 25, 2026 13:53

Pull request was converted to draft

@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

CORA - Pending Reviewers

All codeowners have approved! ✅

Legend: ✅ Approved | ❌ Changes Requested | 💬 Commented | 🚫 Dismissed | ⏳ Pending | ❓ Unknown

For more details, see the full review summary.

@tarcisiozf
tarcisiozf force-pushed the DEVSVCS-5859/fix-early-returns branch from 2ee8c3a to 491a0f7 Compare August 25, 2026 14:54
@tarcisiozf
tarcisiozf force-pushed the DEVSVCS-5859/fix-early-returns branch 2 times, most recently from 156ab43 to 4bb6063 Compare September 8, 2026 13:37
@tarcisiozf
tarcisiozf marked this pull request as ready for review September 8, 2026 13:56
@tarcisiozf
tarcisiozf requested a review from a team as a code owner September 8, 2026 13:56
@tarcisiozf
tarcisiozf enabled auto-merge September 8, 2026 14:31
Comment thread core/utils/crelimits/gate.go Outdated
Comment thread core/utils/crelimits/gate.go Outdated
@tarcisiozf
tarcisiozf force-pushed the DEVSVCS-5859/fix-early-returns branch from ab31c36 to 22de8ae Compare September 8, 2026 16:05
DylanTinianov
DylanTinianov previously approved these changes Sep 8, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Several new limiter error logs claim “using the default value” even when the code proceeds with limiter-returned values, and one true default-fallback path is missing the new fallback metric increment.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

core/services/workflows/v2/engine.go:1068

  • This log message says "using the default value", but the code continues with maxUserLogEventsPerExecution as returned by the limiter. If the limiter can return a non-default value together with an advisory error, this message will be inaccurate/misleading.
		lggr.Errorw("Failed to get log event limit; using the default value", "err", err)

core/services/workflows/v2/engine.go:1484

  • When limiter.Limit returns an error, this log message claims the default is being used, but the function still returns the limiter-provided value if it is > 0. Also, when the function actually falls back to default due to a non-sensical (<=0) value, it doesn't increment the new limit-read fallback metric.
		e.logger().Errorw("Failed to get DON time request timeout; using the default value", "err", err)
	}
	if limit <= 0 {
		e.logger().Warnw("DON time request timeout is less than or equal to 0, using default timeout", "defaultTimeout", defaultTimeout)
		return defaultTimeout
  • Files reviewed: 22/32 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread core/services/workflows/v2/engine.go Outdated
Comment thread core/services/workflows/v2/config.go Outdated

@patrickhuie19 patrickhuie19 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mostly lgtm, nice! Requesting changes to remove metering/billing changes from scope.

// calling DON so it cannot be spoofed. All F+1 aggregated requests share this
// payload (WorkflowDonID is part of the request hash), so a single check here
// covers the quorum. The gate is guaranteed non-nil by NewServerRequest.
enabled, gerr := workflowDONBindingGate.Limit(ctx)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/nit generally methods that perform a bool check are most readable if named IsVerb i.e. IsOpen

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/ nit IsOpen > Open for this use case

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tm := e.metrics.With(platform.KeyTriggerID, triggerID)
tm.IncrementTriggerEventDroppedTotal(ctx, monitoring.TriggerDropReasonQueueAgeLimitReadFailed)
return ErrEnqueueFailed
// A settings read failure is not a reason to drop a customer's trigger event:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmank88 doesn't this depend on how persistent the read failure is? the risk is overwhelming our systems. cc @wentzeld

@jmank88 jmank88 Sep 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need a stronger motive than just that the Limit method now returns a usable value. It does not seem correct to just use that blindly in every case. What makes this case exceptional? Should we be inspecting the type of error?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably enumerate the relevant cases but I am thinking that we at least need a "missing tenant" error because that indicates programmer mistake, not a degraded system.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fallback is to the compiled defaults, not to "no limit". The same values we run on when there's no JD override.

@tarcisiozf tarcisiozf Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add a special case to handle missing tenant, need this common PR to expose error

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added the IsErrRecoverable and handled the cases in the engine

// instead of vanishing. Deliberately NOT used for shard-ownership denials just below:
// every node outside the owning shard denies each execution, so emitting there
// would publish DON-wide failures for runs that actually succeeded on the owner.
emitDroppedExecution := func(cause error, class events.ErrorClassification) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to double check - what is the envisioned e2e flow here? We emit a TriggerExecutionStarted event. AFAICT, the UI can look for a TriggerExecutionStarted event and see there are no ExecutionStarted/Finished events. Is the point that if you've reached your workflow execution limit that this is surfaced in the UI/CLI? I do see error being propagated for workflow failures in staging to the UI.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your mental model is correct, TriggerExecutionStarted is emitted via the trigger capability path, and ExecutionStarted/ExecutionFinished from the engine. One of the goals here is to remove two return paths that may prevent one or both events of being emitted.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About errors already reaching the UI in staging, we're not adding a new surfacing path, we're routing failures that previously emitted nothing into the ExecutionFinished + ClassifiedStatus channel that already works.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the execution limit question, executionsSemaphore.Wait blocks rather than rejects, so hitting the concurrency limit just queues the event. It only errors if the limiter is closed or the ctx is done, and that path continues with a metric and no execution events

Comment thread core/services/workflows/v2/engine.go Outdated
Comment thread core/services/workflows/v2/engine.go Outdated
@tarcisiozf
tarcisiozf force-pushed the DEVSVCS-5859/fix-early-returns branch from c235c52 to cb41e65 Compare September 10, 2026 12:59
@tarcisiozf
tarcisiozf force-pushed the DEVSVCS-5859/fix-early-returns branch from cb41e65 to 7008091 Compare September 11, 2026 00:29
@tarcisiozf
tarcisiozf force-pushed the DEVSVCS-5859/fix-early-returns branch from 1f928b4 to 02cca92 Compare September 14, 2026 20:45
@cl-sonarqube-production

Copy link
Copy Markdown

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants