Skip to content

fix: preserve retry params for dotenv resolution#2267

Merged
yohamta0 merged 3 commits into
mainfrom
fix-retry-runtime-params
Jun 5, 2026
Merged

fix: preserve retry params for dotenv resolution#2267
yohamta0 merged 3 commits into
mainfrom
fix-retry-runtime-params

Conversation

@yohamta0

@yohamta0 yohamta0 commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Preserves raw retry ParamsList through retry restoration so dotenv paths such as .env.${COL} resolve with logical values and parameter values containing spaces survive retries.

Changes

  • Use raw ParamsList for dotenv loading and quote runtime params only at parser/reload boundaries.
  • Rehydrate retry params consistently in CLI, API reschedule/subprocess, scheduler, and distributed worker paths.
  • Add regression coverage for dotenv parameter expansion, values with spaces, reschedule, distributed retry, and worker cleanup on invalid previous status.

Related Issues

Fixes #2265

Checklist

  • Code follows the project style guidelines
  • Self-review of the code has been performed
  • Tests have been added or updated as needed
  • Documentation has been updated as needed
  • Changes have been tested locally

Root Cause

Retry restored status.ParamsList through quoted parser tokens before dotenv loading. That changed COL=foo into COL="foo" for dotenv path expansion, so .env.${COL} became .env."foo" and missed .env.foo. Some retry paths also relied on task params only and did not rehydrate params from embedded previous status.

Testing

  • go test ./internal/cmd ./internal/core/spec ./internal/service/frontend/api/v1 ./internal/service/scheduler ./internal/service/worker -count=1

Summary by cubic

Preserves raw retry params during dotenv resolution so .env.${COL} resolves correctly and values with spaces aren’t split. Extends this to reschedule and distributed retry paths to keep ParamsList intact across CLI, API/subprocess, scheduler, and remote worker. Fixes #2265.

  • Bug Fixes
    • Load dotenv using the unquoted previous ParamsList; quote only when re-parsing to keep space-containing values intact.
    • Recompute runtime params before env resolution and apply them to DAG cloning so .env expansion is accurate.
    • Standardize retry param restoration across reschedule and distributed paths: reschedule prefers snapshot-preserved params and persists ParamsList; distributed retry passes PreviousStatus.ParamsList to workers with a legacy Params fallback.

Written for commit 61ceaf6. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Improved preservation and restoration of runtime parameters when retrying DAG runs.
    • Fixed handling of parameterized dotenv file paths during retry operations.
    • Enhanced support for parameter values containing special characters (spaces) during retries.

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR fixes parameter loss during DAG step retry by preserving status.ParamsList through restoration and rebuilding operations. Changes span the spec layer (param quoting and resolution), command-layer retry restoration, API snapshot handling, scheduler/worker task execution, and comprehensive integration tests validating dotenv expansion with parameterized filenames.

Changes

Runtime parameter preservation for retry operations

Layer / File(s) Summary
Spec-layer runtime param resolution and quoting
internal/core/spec/dparams_runtime.go, internal/core/spec/runtime_env.go, internal/core/spec/runtime_params_external_test.go, internal/core/spec/runtime_env_external_test.go
ResolveEnvWithWarnings now resolves runtime params up-front via new resolveRuntimeParamsForEnv helper and assigns them to cloned.Params before env recomputation; runtimeParamLoadOptions applies QuoteRuntimeParams to []string param inputs before calling WithParams; tests validate param preservation with spaces and dotenv expansion with runtime-resolved params.
Command-layer DAG restoration from retry status
internal/cmd/helper.go, internal/cmd/export_test.go, internal/cmd/retry_params_external_test.go
restoreDAGFromStatus copies and quotes status.ParamsList, assigns it to dag.Params, loads dotenv, and passes quoted params as override to rebuildDAGFromYAML for correct expansion of parameterized dotenv paths; rebuildDAGFromYAML accepts optional paramsOverride to select which params to use during YAML rebuild; test validates the full flow including dotenv expansion result.
API-layer DAG run snapshot restoration
internal/service/frontend/api/v1/dagruns.go
restoreDAGRunSnapshot mirrors command-layer logic by copying/quoting status.ParamsList and passing quoted params as override to rebuildDAGRunSnapshotFromYAML; prepareRetryDAGForSubprocess now passes raw status.ParamsList to ResolveEnvWithWarnings instead of pre-quoting.
Scheduler and worker task param fallback
internal/service/scheduler/dag_executor.go, internal/service/worker/handler.go, internal/service/worker/export_test.go, internal/service/worker/remote_handler.go
Local scheduler execution and remote DAG loading now fall back to previousStatusParams(task) helper when current task has no params, extracting raw status.ParamsList from prior run; remote paths quote and apply fallback params via spec.WithParams; test helper LoadRemoteTaskDAGForTest enables worker-layer testing.
Integration tests validating retry param preservation
internal/service/worker/remote_retry_params_external_test.go
Comprehensive test validates that worker.LoadRemoteTaskDAGForTest loads a retry DAG using prior run's ParamsList, expands parameterized dotenv filenames (.env.${COL}), and correctly resolves environment variables from loaded dotenv files.

Sequence Diagrams

sequenceDiagram
  participant PrevRun as Previous DAG Run
  participant Status as status.ParamsList
  participant Restore as restoreDAGFromStatus
  participant Quote as QuoteRuntimeParams
  participant Rebuild as rebuildDAGFromYAML
  participant Dotenv as LoadDotEnv
  participant Env as dag.Env
  
  PrevRun->>Status: Capture ParamsList<br/>(e.g., COL=foo)
  Status->>Restore: ParamsList passed to restore
  Restore->>Restore: Copy ParamsList to dag.Params
  Restore->>Dotenv: Load unparameterized .env files
  Restore->>Quote: Quote(ParamsList, dag.ParamDefs)
  Quote->>Restore: Quoted params
  Restore->>Rebuild: Call with paramsOverride=quoted
  Rebuild->>Rebuild: Use override for spec.WithParams
  Rebuild->>Dotenv: Expand ".env.${COL}" → ".env.foo"<br/>Load .env.foo
  Dotenv->>Env: TARGET_TABLE=foo added to env
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • dagucloud/dagu#2225: Modifies retry DAG restoration plumbing in internal/cmd/export_test.go and internal/cmd/helper.go with related restoreDAGFromStatus and rebuildDAGFromYAML changes.
  • dagucloud/dagu#2233: Updates restoreDAGFromStatus in internal/cmd/helper.go with dotenv loading and runtime param quoting/override logic that parallels the param-preservation pattern in this PR.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: preserve retry params for dotenv resolution' accurately summarizes the main change: preserving raw retry parameters during dotenv loading to fix parameter resolution in retried steps.
Linked Issues check ✅ Passed The PR directly addresses all objectives from issue #2265 [#2265]: preserving parameter values in retries, maintaining dotenv expansion for parameterized paths like .env.${COL}, and preventing parameter loss across retry flows through comprehensive changes across CLI, API, scheduler, and worker paths.
Out of Scope Changes check ✅ Passed All code changes directly support the stated objective of preserving retry parameters for dotenv resolution; file modifications target parameter handling in retry paths across all execution entry points (CLI, API, scheduler, worker) without unrelated changes.
Description check ✅ Passed The pull request description comprehensively covers the summary, changes, related issues, and testing details with all required template sections completed.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-retry-runtime-params

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/service/frontend/api/v1/dagruns.go`:
- Around line 569-581: rescheduleDAGRun is still using the lossy
exec.DAGRunStatus.Params when useCurrentDAGFile==true, which reintroduces
space-splitting bugs; update rescheduleDAGRun to prefer the preservedParams
returned by restoreDAGRunSnapshot (the quoted, safe form) instead of
status.Params when available (fall back to status.Params only if preservedParams
is empty), and ensure you reference restoreDAGRunSnapshot, rescheduleDAGRun,
preservedParams and exec.DAGRunStatus.Params when making the change.

In `@internal/service/scheduler/dag_executor.go`:
- Around line 240-245: The fix only handled the local retry path
(prepareDAGForSubprocess) but scheduled distributed retries still populate
task.Params from exec.DAGRunStatus.Params which flattens values with spaces;
update the code that prepares tasks for remote/scheduled retries to use
previousStatus.ParamsList (or otherwise preserve/round-trip quoting) instead of
previousStatus.Params so the remote worker receives the ParamsList
representation; look for code paths that set task.Params or read
exec.DAGRunStatus.Params during scheduled retry and switch them to use
ParamsList (or pass the original ParamsList through) to prevent unquoted
flattening.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7bf40df0-5703-4b4d-8791-12695883dcb2

📥 Commits

Reviewing files that changed from the base of the PR and between 3bd56d5 and 6ea64bc.

📒 Files selected for processing (13)
  • internal/cmd/export_test.go
  • internal/cmd/helper.go
  • internal/cmd/retry_params_external_test.go
  • internal/core/spec/dparams_runtime.go
  • internal/core/spec/runtime_env.go
  • internal/core/spec/runtime_env_external_test.go
  • internal/core/spec/runtime_params_external_test.go
  • internal/service/frontend/api/v1/dagruns.go
  • internal/service/scheduler/dag_executor.go
  • internal/service/worker/export_test.go
  • internal/service/worker/handler.go
  • internal/service/worker/remote_handler.go
  • internal/service/worker/remote_retry_params_external_test.go

Comment on lines 569 to +581
func restoreDAGRunSnapshot(ctx context.Context, dag *core.DAG, status *exec.DAGRunStatus) (*core.DAG, string, error) {
quotedParams := spec.QuoteRuntimeParams(status.ParamsList, dag.ParamDefs)
dag.Params = quotedParams
runtimeParams := append([]string(nil), status.ParamsList...)
dag.Params = runtimeParams
dagwarning.LoadDotEnv(ctx, dag)

restored, err := rebuildDAGRunSnapshotFromYAML(ctx, dag)
quotedParams := spec.QuoteRuntimeParams(runtimeParams, dag.ParamDefs)
restored, err := rebuildDAGRunSnapshotFromYAML(ctx, dag, quotedParams)
if err != nil {
return nil, "", err
}

return restored, strings.Join(quotedParams, " "), nil
preservedParams := strings.Join(quotedParams, " ")
return restored, preservedParams, nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

The preserved retry params are still bypassed on current-file reschedules.

This helper now returns the correctly quoted preservedParams, but rescheduleDAGRun still prefers status.Params whenever useCurrentDAGFile=true. That reintroduces the space-splitting bug on that path, because status.Params is the lossy joined form.

🛠️ Suggested change
-	currentFileParams := status.Params
-	if currentFileParams == "" {
-		currentFileParams = preservedSnapshotParams
-	}
+	currentFileParams := preservedSnapshotParams
+	if currentFileParams == "" {
+		currentFileParams = status.Params
+	}

Based on learnings: exec.DAGRunStatus.Params stores unquoted inline values, so it does not safely round-trip values containing spaces.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/service/frontend/api/v1/dagruns.go` around lines 569 - 581,
rescheduleDAGRun is still using the lossy exec.DAGRunStatus.Params when
useCurrentDAGFile==true, which reintroduces space-splitting bugs; update
rescheduleDAGRun to prefer the preservedParams returned by restoreDAGRunSnapshot
(the quoted, safe form) instead of status.Params when available (fall back to
status.Params only if preservedParams is empty), and ensure you reference
restoreDAGRunSnapshot, rescheduleDAGRun, preservedParams and
exec.DAGRunStatus.Params when making the change.

Comment on lines 240 to 245
// Local execution
var params any
if previousStatus != nil {
params = spec.QuoteRuntimeParams(previousStatus.ParamsList, dag.ParamDefs)
params = previousStatus.ParamsList
}
dag, err := e.prepareDAGForSubprocess(ctx, dag, params)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

This only fixes the local retry path.

Scheduled distributed retries still populate the task with previousStatus.Params in the branch above, and the remote worker prefers task.Params over previous_status. So a value like COL=foo bar is still flattened before it reaches the worker, even though the local branch now uses ParamsList.

🛠️ Suggested change
-		if previousStatus != nil && previousStatus.Params != "" {
+		if previousStatus != nil && len(previousStatus.ParamsList) == 0 && previousStatus.Params != "" {
 			taskOpts = append(taskOpts, executor.WithTaskParams(previousStatus.Params))
 		}

Based on learnings: exec.DAGRunStatus.Params stores unquoted inline values, so it does not safely round-trip values containing spaces.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/service/scheduler/dag_executor.go` around lines 240 - 245, The fix
only handled the local retry path (prepareDAGForSubprocess) but scheduled
distributed retries still populate task.Params from exec.DAGRunStatus.Params
which flattens values with spaces; update the code that prepares tasks for
remote/scheduled retries to use previousStatus.ParamsList (or otherwise
preserve/round-trip quoting) instead of previousStatus.Params so the remote
worker receives the ParamsList representation; look for code paths that set
task.Params or read exec.DAGRunStatus.Params during scheduled retry and switch
them to use ParamsList (or pass the original ParamsList through) to prevent
unquoted flattening.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 13 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread internal/service/worker/remote_handler.go
@yohamta0 yohamta0 merged commit d7fe20f into main Jun 5, 2026
11 checks passed
@yohamta0 yohamta0 deleted the fix-retry-runtime-params branch June 5, 2026 14:49
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.

bug: re-tries loosing parameter value

1 participant