feat: add transactional repository methods (InsertWithTx, CheckLimitsWithTx)#73
Conversation
…WithTx) Add WithTx variants alongside existing methods for transactional usage: - InsertWithTx accepts pgdb.DB parameter for atomic operations - CheckLimitsWithTx accepts pgdb.DB for API consistency - Extract insertInternal/checkLimitsInternal to eliminate duplication - Add nil db validation to InsertWithTx - Add forbidden practice rule: no task/ticket IDs in code - Regenerate mocks for updated interfaces
|
This PR is very large (27 files, 1359 lines changed). Consider breaking it into smaller PRs for easier review. |
|
Consider updating CHANGELOG.md to document this change. If this change doesn't need a changelog entry, add the |
|
Consider updating CHANGELOG.md to document this change. If this change doesn't need a changelog entry, add the |
|
This PR is very large (27 files, 1360 lines changed). Consider breaking it into smaller PRs for easier review. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds transactional entry points and shared internal helpers: Sequence Diagram(s)sequenceDiagram
participant Client
participant Repo as TransactionValidationRepository
participant DB
participant Tracer
Client->>Repo: InsertWithTx(ctx, db, validation)
Repo->>Tracer: Start span "repository.transaction_validation.insert_with_tx"
Repo->>Repo: insertInternal(ctx, db, validation, logger, span, operationName)
Repo->>DB: ExecContext("INSERT INTO transaction_validations", args)
DB-->>Repo: Exec result / error
Repo->>Tracer: HandleSpanError(span, err)
Repo-->>Client: return error | nil
sequenceDiagram
participant Client
participant Service as LimitCheckerService
participant LimitRepo as LimitRepository
participant UsageRepo as UsageCounterRepository
participant DB
participant Tracer
Client->>Service: CheckLimitsWithTx(ctx, db, input)
Service->>Tracer: Start span "service.limit_checker.check_limits_with_tx"
Service->>Service: checkLimitsInternal(ctx, input, logger, span, operationName)
Service->>LimitRepo: List(applicable limits)
LimitRepo-->>Service: limits
Service->>UsageRepo: UpsertAndIncrementAtomic(..., /* may use db */)
UsageRepo-->>Service: updated usage / error
Service->>Tracer: HandleSpanError(span, err)
Service-->>Client: CheckLimitsOutput | error
🚥 Pre-merge checks | ✅ 1 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
🔒 Security Scan Results —
|
| Policy | Status |
|---|---|
| Default non-root user | ✅ Passed |
| No fixable critical/high CVEs | ✅ Passed |
| No high-profile vulnerabilities | ✅ Passed |
| No AGPL v3 licenses | ✅ Passed |
Shallow copy of LimitUsageDetails left the internal Scopes slice aliased with the original entity. Replace copy() with per-element iteration that creates independent Scopes slices.
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/build.yml:
- Line 10: Replace the mutable tag for the reusable workflow reference
"LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@v1.18.1"
with the immutable commit SHA "09f3e9acbe91c58bac6997b4f6f7f2584a6200c5" in both
places it appears (the current occurrences using `@v1.18.1`); update the string to
"LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@09f3e9acbe91c58bac6997b4f6f7f2584a6200c5"
so the workflow is pinned to the exact commit.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: aa391465-582a-4ffd-b9b8-863f2e3d7dae
📒 Files selected for processing (2)
.github/workflows/build.ymlDockerfile
- Add span trade-off documentation comment in InsertWithTx nil check - Add span error annotation for FromEntity failure in insertInternal - Add TODO(T-003) markers for future db parameter wiring in CheckLimitsWithTx - Add TODO(T-003) markers in limit_checker_test.go for future expectations
…methods' of github.com:LerianStudio/tracer into feat/idempotency-key-support--transactional-repository-methods
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
internal/services/query/limit_checker.go (1)
80-92:⚠️ Potential issue | 🔴 Critical
CheckLimitsWithTxstill isn't transactional.
dbis discarded and this method delegates into the same repository path asCheckLimits, so counter mutations can still commit even if the caller rolls back its surrounding transaction. The inline TODO documents the gap, but shipping aWithTxAPI before the repositories honor that handle is still unsafe. Please wiredbthrough repositoryWithTxmethods before exposing this entrypoint, or fail fast/remove it for now.Also applies to: 143-164
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/services/query/limit_checker.go` around lines 80 - 92, The CheckLimitsWithTx entrypoint is not actually transactional because it discards the db parameter and delegates to the same repository path as CheckLimits; either thread the provided db (pgdb.DB) through the underlying repositories using their WithTx (or equivalent) methods so all counter mutations use the caller's transaction, or remove/fail-fast this API until repositories accept the transactional handle; update CheckLimitsWithTx to accept *model.CheckLimitsInput and return *model.CheckLimitsOutput as before but call repo.WithTx(db).<method>…</method> (use the repository names and WithTx methods found in the same package) so that all calls that mutate counters use the transactional repo handle instead of the non-transactional path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/services/query/limit_checker_test.go`:
- Around line 5304-5305: Replace any TODO comments that include task/ticket IDs
(e.g., "TODO(T-003)") with plain "TODO" so they comply with the new no
task/ticket IDs rule; specifically update the comment containing "TODO(T-003):
When repos support WithTx, add gomock.Eq(mockDB) expectations..." to remove
"(T-003)" and do the same for the other occurrence of "TODO(T-003)" around the
later comment (previously noted at the other location), leaving the rest of the
comment text unchanged.
---
Duplicate comments:
In `@internal/services/query/limit_checker.go`:
- Around line 80-92: The CheckLimitsWithTx entrypoint is not actually
transactional because it discards the db parameter and delegates to the same
repository path as CheckLimits; either thread the provided db (pgdb.DB) through
the underlying repositories using their WithTx (or equivalent) methods so all
counter mutations use the caller's transaction, or remove/fail-fast this API
until repositories accept the transactional handle; update CheckLimitsWithTx to
accept *model.CheckLimitsInput and return *model.CheckLimitsOutput as before but
call repo.WithTx(db).<method>…</method> (use the repository names and WithTx
methods found in the same package) so that all calls that mutate counters use
the transactional repo handle instead of the non-transactional path.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: af93c69c-5958-409d-9825-ef43563eb596
📒 Files selected for processing (3)
internal/adapters/postgres/transaction_validation_repository.gointernal/services/query/limit_checker.gointernal/services/query/limit_checker_test.go
FNV-1a 32-bit hash converts UUID to int32 for use with pg_advisory_xact_lock. Deterministic, fast, and well-distributed across the int32 range.
- Add ValidateResult struct with Response and IsDuplicate fields - Add transactionValidationQueryRepo dependency for FindByRequestID - Check for existing record before processing (DD-3: Stripe model) - Duplicate requests return cached response, skip rule/limit eval - Add ErrNilTransactionValidationQueryRepo sentinel error - Update constructor to accept and validate query repo dependency
- Handler uses ValidateResult.IsDuplicate to select status code - HTTP 201 Created for new requests (DD-9) - HTTP 200 OK for duplicate requests returning cached response - Wire transactionValidationQueryRepo in bootstrap config
- TestValidate_DuplicateRequestID_ReturnsOriginal - TestValidate_DuplicateRequestID_NoDoubleCount - TestValidate_DuplicateRequestID_NoAudit - TestValidate_DenyByRule_RetryTolerant - TestValidate_DenyByLimit_RollbackAtomic - TestValidate_Review_RollbackAtomic - TestValidationHandler_Validate_ReturnsCorrectStatusCodes (201/200)
Adapt all existing validation service and handler tests to use the new 6-parameter constructor and ValidateResult return type. Add FindByRequestID mock expectations for non-duplicate flows.
Replace TODO(T-003) markers with NOTE comments per PROJECT_RULES.md rule against task IDs in source code.
Move nil validation check to the top of Insert and InsertWithTx, before GetDB() or span creation. Avoids unnecessary DB connection and OpenTelemetry overhead for programming errors. The check in insertInternal is kept as defense-in-depth.
|
This PR is very large (35 files, 2333 lines changed). Consider breaking it into smaller PRs for easier review. |
|
No description provided. |
The wrap-around is intentional: pg_advisory_xact_lock accepts int32, and we need the full hash range including negative values.
|
This PR is very large (35 files, 2333 lines changed). Consider breaking it into smaller PRs for easier review. |
Summary
Add
WithTxvariants alongside existing repository methods, enabling transactional usage without breaking existing non-transactional callers. This is the foundation for atomic deduplication in the next PR.Changes
Repository Layer
InsertWithTx(ctx, db, entity): Inserts transaction validation using providedpgdb.DBparameterinsertInternal: Extracted shared logic betweenInsertandInsertWithTx(DRY)dbis nilService Layer
CheckLimitsWithTx(ctx, db, input): Acceptspgdb.DBfor API consistency (db param reserved for future transactional repo support)checkLimitsInternal: Extracted shared logic betweenCheckLimitsandCheckLimitsWithTx(DRY)Interfaces
command.TransactionValidationRepository: AddedInsertWithTxquery.LimitChecker: AddedCheckLimitsWithTxCode Quality
Design Decisions
txpassed aspgdb.DBparameter (no TxManager)WithTxmethods are additive -- existing methods unchanged, backward compatibleCheckLimitsWithTxacceptsdbfor API consistency; underlying repos will use it when they support transactional operationsBackward Compatibility
InsertandCheckLimitsmethods unchanged