Skip to content

Fix: Add transaction protection for subtask creation#368

Open
lxcxjxhx wants to merge 4 commits into
vxcontrol:mainfrom
lxcxjxhx:fix/subtask-transaction-protection
Open

Fix: Add transaction protection for subtask creation#368
lxcxjxhx wants to merge 4 commits into
vxcontrol:mainfrom
lxcxjxhx:fix/subtask-transaction-protection

Conversation

@lxcxjxhx

@lxcxjxhx lxcxjxhx commented Jul 7, 2026

Copy link
Copy Markdown

Problem

The GenerateSubtasks and RefineSubtasks functions in subtasks.go create multiple subtasks in a loop without transaction protection. If any subtask creation fails midway, the database is left in an inconsistent state with partial subtasks created.

Solution

Added transaction support by passing *sql.DB through the controller chain and wrapping subtask operations in transactions:

Architecture changes:

  • Added RawDB *sql.DB field to FlowContext (context.go)
  • Added rawDB *sql.DB field to flowWorkerCtx (flow.go)
  • Added rawDB *sql.DB field to flowController and updated NewFlowController signature (flows.go)
  • Updated main.go to pass the database connection to the flow controller

Transaction implementation:

  • GenerateSubtasks: Wraps all CreateSubtask calls in a transaction with proper rollback on error
  • RefineSubtasks: Wraps delete and create operations in a single transaction to ensure atomicity

Changes

  • backend/cmd/pentagi/main.go: Pass db to NewFlowController
  • backend/pkg/controller/context.go: Add RawDB *sql.DB to FlowContext
  • backend/pkg/controller/flow.go: Add rawDB to flowWorkerCtx and propagate to FlowContext
  • backend/pkg/controller/flows.go: Add rawDB to flowController, update constructor signature
  • backend/pkg/controller/subtasks.go: Implement transaction-protected subtask operations

Testing

  • Code compiles successfully with go build
  • Transaction logic follows Go best practices with proper defer rollback
  • Error handling includes transaction rollback and commit verification

Impact

This fix ensures data consistency when creating or refining subtasks. If any operation fails, the entire transaction is rolled back, preventing partial subtask creation that could lead to inconsistent task states.

The original code had TODO comments acknowledging this issue:

  • Line 80: // TODO: change it to insert subtasks in transaction
  • Line 118: // TODO: change it to insert subtasks in transaction and union it with delete ones

This PR resolves both TODOs.

lxcxjxhx added 4 commits July 7, 2026 08:49
- Fix double timeout padding in Handle() method that inflated user-requested timeouts by 5 seconds
- Fix incorrect log type in WriteFile() method (stdin -> stdout) for proper log stream classification
- Fix incomplete file read in ReadFile() method by using io.ReadFull instead of single Read() call

These bugs affected command execution timeout handling, log type correctness, and file read completeness.
All fixes are minimal, targeted, and maintain backward compatibility while improving correctness.
- Remove defer close(q.queue) from reader() to prevent double close
- Add explicit close(q.queue) in Stop() after cancel() to ensure workers exit
- This fixes goroutine leak when Stop() is called while workers are still processing

The issue: when Stop() calls cancel(), the reader() might not exit immediately,
and workers waiting on q.queue channel would block forever, causing goroutine leak.
- Pass *sql.DB through controller chain to enable transactions
- Wrap GenerateSubtasks in transaction with proper rollback
- Wrap RefineSubtasks delete+create in single transaction
- Ensures atomicity and prevents partial subtask creation
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.

1 participant