Skip to content

Comments

feat: default execution mode#1642

Merged
yottahmd merged 7 commits intomainfrom
unified-exec-dispatch
Feb 7, 2026
Merged

feat: default execution mode#1642
yottahmd merged 7 commits intomainfrom
unified-exec-dispatch

Conversation

@yottahmd
Copy link
Collaborator

@yottahmd yottahmd commented Feb 7, 2026

Summary by CodeRabbit

  • New Features
    • Added configurable server-wide default execution mode (local or distributed) to control how DAGs are executed by default
    • Added ability to force local execution of individual DAGs using workerSelector: local in DAG specifications
    • Improved consistency of execution dispatch decisions across all execution paths

@coderabbitai
Copy link

coderabbitai bot commented Feb 7, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review
📝 Walkthrough

Walkthrough

This PR introduces a configurable default execution mode system across Dagu. Users can set a server-wide DefaultExecMode (local or distributed) via config or environment variable. DAGs can override this by using workerSelector: "local" to force local execution. A new centralized ShouldDispatchToCoordinator() function determines whether to dispatch based on force-local flag, worker selector, coordinator availability, and default mode. This logic propagates through CLI, API, scheduler, and runtime components.

Changes

Cohort / File(s) Summary
Configuration & Defaults
internal/cmn/config/config.go, internal/cmn/config/config_test.go, internal/cmn/config/definition.go, internal/cmn/config/loader.go, internal/cmn/config/loader_test.go
Added ExecutionMode type with ExecutionModeLocal/ExecutionModeDistributed constants and DefaultExecMode field to Config. Updated validation, loader, and test fixtures. Environment binding added for DEFAULT_EXECUTION_MODE.
Core Dispatch Logic
internal/core/dispatch.go, internal/core/dispatch_test.go, internal/core/dag.go
Added ShouldDispatchToCoordinator() function to centralize dispatch decisions. Added ForceLocal boolean field to DAG struct with comprehensive test coverage.
DAG Specification & Schema
internal/core/spec/dag.go, internal/core/spec/dag_test.go, internal/cmn/schema/dag.schema.json
Changed WorkerSelector type from map[string]string to any to support both map and "local" string. Added custom transformer to parse input and derive ForceLocal flag. Updated JSON schema with oneOf union type.
CLI Command Handlers
internal/cmd/context.go, internal/cmd/dry.go, internal/cmd/restart.go, internal/cmd/retry.go, internal/cmd/start.go
Propagated DefaultExecMode from config to agent options across all command paths. Updated NewScheduler to pass execution mode to NewDAGExecutor. Refactored start handler to use ShouldDispatchToCoordinator() for dispatch decisions.
API Service
internal/service/frontend/api/v1/api.go, internal/service/frontend/api/v1/dagruns.go, internal/service/frontend/api/v1/dags.go
Added defaultExecMode field to API struct. Updated retry logic to use ShouldDispatchToCoordinator(). Added dispatchStartToCoordinator() helper for distributed DAG starts with timeout support. Updated imports and aliases for runtime package.
Scheduler Service
internal/service/scheduler/dag_executor.go, internal/service/scheduler/dag_executor_test.go, internal/service/scheduler/queue_processor_test.go, internal/service/scheduler/scheduler.go
Added defaultExecMode parameter to NewDAGExecutor constructor. Updated shouldUseDistributedExecution() to delegate to ShouldDispatchToCoordinator(). Updated all test fixtures.
Agent & Runtime
internal/runtime/agent/agent.go, internal/runtime/context.go, internal/runtime/executor/dag_runner.go, internal/service/worker/handler_test.go, internal/service/worker/remote_handler.go
Added DefaultExecMode field to Agent options and context. Added re-export of WithDefaultExecMode in runtime context. Large refactor of dag_runner.go to use exec alias consistently, updating all dispatcher, context, and command types. Updated worker handler import aliases.
Test Utilities
internal/test/helper.go, internal/test/scheduler.go
Propagated DefaultExecMode through test helper and scheduler setup functions.
Documentation & Miscellaneous
rfcs/010-immediate-execution-worker-selector.md, internal/runtime/builtin/chat/tools.go
Added RFC documenting the new execution mode feature. Minor import alias fix in chat tools.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • PR #1449: Both modify runtime/context.go re-export surface to expose new execution mode configuration helpers.
  • PR #1573: Both refactor coordinator dispatch logic and CLI execution paths to centralize decision-making across start/retry/restart commands.
  • PR #1564: Both modify the scheduler's DAGExecutor constructor signature and execution mode routing behavior.
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 56.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: default execution mode' clearly and concisely describes the main feature being introduced—a configurable default execution mode for DAGs.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch unified-exec-dispatch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@internal/core/spec/dag.go`:
- Around line 916-973: buildWorkerSelector currently rejects scalar YAML values
in the map[string]any and map[any]any cases instead of coercing them to strings;
update buildWorkerSelector to convert non-string scalar values using fmt.Sprint
before trimming (for the case map[string]any, if val is not a string call
fmt.Sprint(val) and proceed, and for map[any]any after validating/obtaining
strKey similarly convert non-string val with fmt.Sprint), preserving existing
error handling for non-string keys in map[any]any and keeping the "local" string
behavior unchanged; reference function name buildWorkerSelector and the
map[string]any / map[any]any switch cases when making the change.

In `@rfcs/010-immediate-execution-worker-selector.md`:
- Around line 55-57: The fenced code block containing
"DAGU_DEFAULT_EXECUTION_MODE=distributed" is missing a language identifier;
update the markdown block around that line to include a language hint (e.g.,
"sh" or "bash") so the block becomes a shell snippet (add the identifier after
the opening backticks) to satisfy MD040 linting.
🧹 Nitpick comments (4)
internal/service/worker/handler_test.go (1)

7-7: Consider a clearer alias for the standard runtime package.

osrt is not immediately recognizable as the Go standard library runtime package. A more descriptive alias like goruntime or stdruntime would improve readability at the single usage site (Line 201).

♻️ Suggested rename
-	osrt "runtime"
+	goruntime "runtime"

And at line 201:

-	if osrt.GOOS == "windows" {
+	if goruntime.GOOS == "windows" {
internal/core/dispatch_test.go (1)

10-61: Well-structured table-driven test covering key dispatch scenarios.

Follows the project's testing conventions. Consider adding a case for an empty/unknown ExecutionMode string to verify the function defaults safely (even if config loading prevents it, defense-in-depth is useful for a public function).

Optional: additional edge case
+		{
+			name:           "unknown defaultMode — treated as local",
+			dag:            &DAG{},
+			hasCoordinator: true,
+			defaultMode:    config.ExecutionMode("unknown"),
+			want:           false,
+		},
internal/service/frontend/api/v1/dags.go (2)

919-962: Duplicated timeout computation in local vs. distributed paths.

Lines 922–925 and 948–951 repeat the identical GOOS-based timeout logic. Consider extracting a small helper to reduce duplication and ensure both paths stay in sync.

♻️ Suggested helper
+func startTimeout() time.Duration {
+	if osrt.GOOS == "windows" {
+		return 10 * time.Second
+	}
+	return 5 * time.Second
+}
+
 func (a *API) startDAGRunWithOptions(ctx context.Context, dag *core.DAG, opts startDAGRunOptions) error {
 	// Check if this DAG should be dispatched to the coordinator for distributed execution
 	if core.ShouldDispatchToCoordinator(dag, a.coordinatorCli != nil, a.defaultExecMode) {
-		timeout := 5 * time.Second
-		if osrt.GOOS == "windows" {
-			timeout = 10 * time.Second
-		}
-		return a.dispatchStartToCoordinator(ctx, dag, opts.dagRunID, timeout)
+		return a.dispatchStartToCoordinator(ctx, dag, opts.dagRunID, startTimeout())
 	}
 	...
-	timeout := 5 * time.Second
-	if osrt.GOOS == "windows" {
-		timeout = 10 * time.Second
-	}
+	timeout := startTimeout()

888-917: Coordinator dispatch path looks correct, but consider the timeout adequacy.

The dispatchStartToCoordinator method dispatches to the coordinator and waits up to 5s (10s on Windows) for the DAG status to transition from NotStarted. In a distributed setup, the coordinator must select a worker, forward the task, and the worker must begin execution — all within that window. If the coordinator or worker pool is under load, this timeout may be too aggressive, resulting in a spurious HTTP 500 even though the DAG will eventually start.

If this is acceptable for now (e.g., coordinator dispatch is expected to be fast), a short comment documenting the assumption would help future readers.

@ghansham
Copy link

ghansham commented Feb 7, 2026

Should we hide the distributed execution related UI elements based on this?

@yottahmd
Copy link
Collaborator Author

yottahmd commented Feb 7, 2026

@ghansham No, I don't think so. The setting is just default, so distributed execution can be used even defaultExecutionMode = local.

@yottahmd yottahmd merged commit 8a67644 into main Feb 7, 2026
5 checks passed
@yottahmd yottahmd deleted the unified-exec-dispatch branch February 7, 2026 13:47
@codecov
Copy link

codecov bot commented Feb 7, 2026

Codecov Report

❌ Patch coverage is 77.58621% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.46%. Comparing base (d3150e7) to head (486f2f1).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
internal/core/spec/dag.go 56.25% 17 Missing and 4 partials ⚠️
internal/cmd/start.go 50.00% 1 Missing and 1 partial ⚠️
internal/cmn/config/loader.go 71.42% 1 Missing and 1 partial ⚠️
internal/runtime/executor/dag_runner.go 95.45% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1642      +/-   ##
==========================================
- Coverage   69.83%   69.46%   -0.38%     
==========================================
  Files         332      333       +1     
  Lines       37327    37409      +82     
==========================================
- Hits        26068    25986      -82     
- Misses       9188     9223      +35     
- Partials     2071     2200     +129     
Files with missing lines Coverage Δ
internal/cmd/context.go 70.53% <100.00%> (ø)
internal/cmd/dry.go 79.22% <100.00%> (+0.27%) ⬆️
internal/cmd/restart.go 58.59% <100.00%> (+0.32%) ⬆️
internal/cmd/retry.go 72.52% <100.00%> (+0.30%) ⬆️
internal/cmn/config/config.go 76.28% <100.00%> (+2.13%) ⬆️
internal/core/dag.go 91.20% <ø> (ø)
internal/core/dispatch.go 100.00% <100.00%> (ø)
internal/core/exec/context.go 91.11% <100.00%> (+0.41%) ⬆️
internal/runtime/agent/agent.go 68.22% <100.00%> (+0.08%) ⬆️
internal/runtime/builtin/chat/tools.go 89.93% <100.00%> (ø)
... and 8 more

... and 9 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d3150e7...486f2f1. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ghansham
Copy link

ghansham commented Feb 7, 2026

@ghansham No, I don't think so. The setting is just default, so distributed execution can be used even defaultExecutionMode = local.

Yeah Later I realized. It is default mode

This was referenced Feb 8, 2026
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.

2 participants