Skip to content

feat: context aware DoWithResult - Must be merged after 2012#4137

Merged
Flo4604 merged 10 commits intomainfrom
eng-2011
Oct 28, 2025
Merged

feat: context aware DoWithResult - Must be merged after 2012#4137
Flo4604 merged 10 commits intomainfrom
eng-2011

Conversation

@ogzhanolguncu
Copy link
Contributor

What does this PR do?

This PR adds context aware DoWithResult - DoWithResultContext. To make this as robust as possible we've introduced two new methods to pkg/retry called DoContext and DoWithResultContext. Reason for introducing new methods are we need to be reactive to context changes(cancels and deadlines) with regular still its impossible to cut the flow when cancel invoked or deadlines passed.

Due to duplication on pkg/db/retry.go we also had to make it reusable so we can share the same initialization logic.

Fixes #3828

If there is not an issue for this, please create one first. This is used to tracking purposes and also helps use understand why this PR exists

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

  • Make sure tests are passing
  • Make sure those actions are satisfied.
image - Notes: "**Update ShouldRetry logic to return false for context.Canceled and context.DeadlineExceeded**" This is a redundant criteria because we are already checking the context errors before checking the `shouldRetry` logic. - "**Modification of existing WithRetry behavior**" Behavior is still intact we just made it reusable to prevent duplication.

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • [x] My changes don't cause any responsiveness issues

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Unkey Docs if changes were necessary

@linear
Copy link

linear bot commented Oct 22, 2025

@changeset-bot
Copy link

changeset-bot bot commented Oct 22, 2025

⚠️ No Changeset found

Latest commit: c9e4091

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Oct 22, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
dashboard Ready Ready Preview Comment Oct 28, 2025 9:53am
engineering Ready Ready Preview Comment Oct 28, 2025 9:53am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 22, 2025

📝 Walkthrough

Walkthrough

Adds a context-aware retry API and migrates several call sites to use it: introduces context-aware retry functions in the retry and db packages, updates tests for context behavior, and replaces prior db.WithRetry(...) calls with db.WithRetryContext(ctx, ...) in handlers and services.

Changes

Cohort / File(s) Summary
Retry core
go/pkg/retry/retry.go, go/pkg/retry/retry_test.go
Added context-aware retry methods: DoContext and DoWithResultContext[T any] with tests for cancellation, deadlines, and backoff behavior.
DB retry wrapper
go/pkg/db/retry.go, go/pkg/db/retry_test.go
Added WithRetryContext[T any](ctx context.Context, fn func() (T, error)) (T, error), DefaultAttempts, backoffStrategy, and shouldRetryError; tests updated/added for context cancellation and deadline semantics.
API handlers
go/apps/api/routes/v2_ratelimit_delete_override/handler.go, go/apps/api/routes/v2_ratelimit_limit/handler.go
Replaced db.WithRetry(...) with db.WithRetryContext(ctx, ...) for namespace lookups; consolidated Request/Response type declarations into single type blocks (formatting only).
Services
go/internal/services/keys/get.go, go/internal/services/usagelimiter/limit.go, go/internal/services/usagelimiter/redis.go
Replaced db.WithRetry(...) with db.WithRetryContext(ctx, ...) to propagate context into DB retry calls; minor formatting edits.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant WithRetryContext as DB.WithRetryContext
    participant Backoff as backoffStrategy
    participant Operation as fn()
    participant Ctx as ctx

    Caller->>WithRetryContext: call WithRetryContext(ctx, fn)
    loop up to DefaultAttempts
        WithRetryContext->>Ctx: check ctx.Done()
        alt ctx canceled / deadline
            WithRetryContext-->>Caller: return ctx.Err()
        else
            WithRetryContext->>Operation: invoke fn()
            Operation-->>WithRetryContext: (result, err)
            alt err == nil
                WithRetryContext-->>Caller: return (result, nil)
            else if shouldRetryError(err)
                WithRetryContext->>Backoff: compute delay
                Backoff-->>WithRetryContext: delay
                WithRetryContext->>Ctx: sleep delay (cancelable)
                alt ctx canceled during sleep
                    WithRetryContext-->>Caller: return ctx.Err()
                end
            else
                WithRetryContext-->>Caller: return (result, err)
            end
        end
    end
    WithRetryContext-->>Caller: return final (result, err)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to:
    • Context checks before attempts and during backoff in go/pkg/retry/retry.go and go/pkg/db/retry.go
    • Correct propagation of ctx into call sites (handler.go, get.go, limit.go, redis.go)
    • shouldRetryError correctness (treating context errors and non-retryable DB errors)
    • Tests in go/pkg/db/retry_test.go and go/pkg/retry/retry_test.go covering cancellation/backoff scenarios

Possibly related PRs

Suggested labels

Core Team

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR includes several changes beyond the explicit scope defined in issue #3828. Most notably, issue #3828 explicitly lists "Migrating existing call sites to use WithRetryContext (can be done progressively in future PRs)" as out-of-scope, yet the PR migrates call sites across five files: v2_ratelimit_delete_override/handler.go, v2_ratelimit_limit/handler.go, keys/get.go, usagelimiter/limit.go, and usagelimiter/redis.go—all updating from db.WithRetry(...) to db.WithRetryContext(ctx, ...). Additionally, the issue marked "Changes to the underlying retry package" as out-of-scope, but the PR adds new methods (DoContext and DoWithResultContext) to pkg/retry/retry.go, though this appears architecturally justified to avoid duplication in pkg/db/retry.go. The refactoring of retry logic to pkg/retry (rather than containing it entirely in pkg/db) represents an expansion beyond the stated scope, though the author justified this as necessary for code reuse. The PR should clarify whether the call site migrations and pkg/retry changes represent intentional scope expansion or unintended deviations from the issue's stated boundaries. If intentional, these changes should be explicitly discussed and justified in the PR description. If unintended, consider separating the call site migrations into a follow-up PR as originally scoped in issue #3828.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "feat: context aware DoWithResult - Must be merged after 2012" accurately describes a core component of the changeset: the introduction of context-aware retry helpers (DoWithResultContext and DoContext). The title is concrete and specific enough that it clearly signals the primary feature being added. While the phrase "Must be merged after 2012" appears to reference a dependency on another PR (not captured in the title), the main technical contribution is well-identified. The title does not capture all aspects of the PR (such as call site migrations), but it appropriately highlights the most significant architectural change.
Linked Issues Check ✅ Passed The PR meets the primary acceptance criteria from issue #3828: it implements WithRetryContext[T any] in the db package with context parameter and generic result type, introduces DoContext and DoWithResultContext methods in pkg/retry to handle context-aware retry logic with pre-attempt context checks, implements exponential backoff (50ms, 100ms, 200ms) with DefaultAttempts constant set to 3, and adds comprehensive tests for context cancellation and deadline scenarios (TestDoContext, TestDoWithResultContext, TestContextErrorsAreNonRetryable). The PR confirms that explicit ShouldRetry handling of context errors is redundant since context is checked before retry decision logic, thus satisfying the intent of that acceptance criterion through architectural design rather than explicit shouldRetryError filtering.
Description Check ✅ Passed The PR description follows the required template structure and includes all essential sections: a clear "What does this PR do?" section with issue reference (#3828), marked change type checkboxes, testing guidance with acceptance actions, and a mostly-completed checklist. The author provides context for why the changes were made ("Due to duplication on pkg/db/retry.go we also had to make it reusable") and includes testing notes and screenshots. While the testing section could be more detailed, the description provides sufficient information about the changeset's intent, scope, and verification approach to meet the template requirements.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch eng-2011

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.

@vercel vercel bot temporarily deployed to Preview – engineering October 27, 2025 13:57 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 27, 2025 13:57 Inactive
@ogzhanolguncu
Copy link
Contributor Author

ogzhanolguncu commented Oct 27, 2025

@Flo4604 we won't able to add harness because its creating circular dependency. Harness importing db, db importing harness.

Copy link
Member

Flo4604 commented Oct 27, 2025

ah yeah thats fine then

@ogzhanolguncu ogzhanolguncu marked this pull request as ready for review October 27, 2025 15:20
Copy link
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
go/internal/services/usagelimiter/redis.go (1)

156-158: Compile error: cannot range over int; start N workers properly

for range replayWorkers is invalid and won’t compile. Use an indexed loop.

Apply:

-for range replayWorkers {
-	go s.replayRequests()
-}
+for i := 0; i < replayWorkers; i++ {
+	go s.replayRequests()
+}
♻️ Duplicate comments (2)
go/pkg/db/retry_test.go (1)

50-63: Skip retry on not found

Asserting IsNotFound and single call addresses prior feedback about specificity.

go/pkg/retry/retry.go (1)

225-233: Good fix: time.NewTimer + select avoids time.After leak.

Thanks for switching away from time.After and stopping the timer on cancel. This addresses the leak pattern raised earlier.

🧹 Nitpick comments (2)
go/pkg/db/retry.go (1)

49-59: Make backoff scalable and reduce herd with jitter

Current table caps at 3 and returns 50ms for n>len(delays). Prefer a scalable exponential with optional cap and jitter to spread retries.

Example:

-func backoffStrategy(n int) time.Duration {
-	delays := []time.Duration{DefaultBackoff, DefaultBackoff * 2, DefaultBackoff * 4}
-	if n <= 0 || n > len(delays) {
-		return DefaultBackoff
-	}
-	return delays[n-1]
-}
+func backoffStrategy(n int) time.Duration {
+	if n < 1 {
+		return DefaultBackoff
+	}
+	// exp backoff with cap
+	d := DefaultBackoff << (n - 1) // 50ms, 100ms, 200ms, 400ms, ...
+	if d > 2*time.Second {
+		d = 2 * time.Second
+	}
+	// add ±20% jitter
+	j := d / 5
+	return d - j + time.Duration(rand.Int63n(int64(2*j+1)))
+}

Remember to seed a rand source or use math/rand/v2 as appropriate.

go/pkg/retry/retry.go (1)

207-234: Inject a timer factory for testability; DoContext currently bypasses r.sleep.

DoContext can’t leverage r.sleep, making tests slower/flaky. Inject a timer factory (similar to sleep hook) to stub timers in tests.

Apply this diff:

diff --git a/go/pkg/retry/retry.go b/go/pkg/retry/retry.go
@@ type retry struct {
 	// overwrite time.Sleep to speed up tests
 	sleep func(d time.Duration)
+	// newTimer allows injecting a fake timer in tests
+	newTimer func(d time.Duration) *time.Timer
 }
@@ func New(applies ...Apply) *retry {
 		shouldRetry: nil, // nil means all errors are retryable
-		sleep:       time.Sleep,
+		sleep:       time.Sleep,
+		newTimer:    time.NewTimer,
 	}
@@ func (r *retry) DoContext(ctx context.Context, fn func() error) error {
-			timer := time.NewTimer(r.backoff(i))
+			timer := r.newTimer(r.backoff(i))
 			select {
 			case <-ctx.Done():
 				timer.Stop()
 				return ctx.Err()
 			case <-timer.C:
 			}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d820283 and e82d178.

📒 Files selected for processing (9)
  • go/apps/api/routes/v2_ratelimit_delete_override/handler.go (2 hunks)
  • go/apps/api/routes/v2_ratelimit_limit/handler.go (2 hunks)
  • go/internal/services/keys/get.go (1 hunks)
  • go/internal/services/usagelimiter/limit.go (1 hunks)
  • go/internal/services/usagelimiter/redis.go (1 hunks)
  • go/pkg/db/retry.go (2 hunks)
  • go/pkg/db/retry_test.go (13 hunks)
  • go/pkg/retry/retry.go (2 hunks)
  • go/pkg/retry/retry_test.go (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-21T15:54:45.198Z
Learnt from: chronark
PR: unkeyed/unkey#3825
File: go/internal/services/usagelimiter/limit.go:38-0
Timestamp: 2025-08-21T15:54:45.198Z
Learning: In go/internal/services/usagelimiter/limit.go, the UpdateKeyCreditsDecrement operation cannot be safely wrapped with db.WithRetry due to the lack of idempotency mechanisms in the current tech stack. Retrying this non-idempotent write operation risks double-charging users if the first attempt commits but the client sees a transient error.

Applied to files:

  • go/internal/services/usagelimiter/limit.go
  • go/internal/services/usagelimiter/redis.go
🧬 Code graph analysis (8)
go/internal/services/usagelimiter/limit.go (1)
go/pkg/db/retry.go (1)
  • WithRetryContext (36-46)
go/pkg/db/retry.go (3)
go/pkg/retry/retry.go (5)
  • DoWithResultContext (242-250)
  • New (64-75)
  • Attempts (82-87)
  • Backoff (92-97)
  • ShouldRetry (116-121)
go/pkg/db/handle_err_no_rows.go (1)
  • IsNotFound (8-10)
go/pkg/db/handle_err_duplicate_key.go (1)
  • IsDuplicateKeyError (7-13)
go/pkg/retry/retry_test.go (1)
go/pkg/retry/retry.go (4)
  • New (64-75)
  • Attempts (82-87)
  • Backoff (92-97)
  • DoWithResultContext (242-250)
go/internal/services/usagelimiter/redis.go (1)
go/pkg/db/retry.go (1)
  • WithRetryContext (36-46)
go/pkg/db/retry_test.go (5)
go/pkg/db/retry.go (1)
  • WithRetryContext (36-46)
go/pkg/retry/retry.go (1)
  • New (64-75)
go/pkg/db/key_find_for_verification.sql_generated.go (1)
  • FindKeyForVerificationRow (92-119)
go/pkg/uid/uid.go (1)
  • KeyPrefix (16-16)
go/pkg/db/key_insert.sql_generated.go (1)
  • InsertKeyParams (51-67)
go/internal/services/keys/get.go (2)
go/pkg/db/retry.go (1)
  • WithRetryContext (36-46)
go/pkg/db/key_find_for_verification.sql_generated.go (1)
  • FindKeyForVerificationRow (92-119)
go/apps/api/routes/v2_ratelimit_delete_override/handler.go (3)
go/apps/api/openapi/gen.go (2)
  • V2RatelimitDeleteOverrideRequestBody (1726-1739)
  • V2RatelimitDeleteOverrideResponseBody (1742-1748)
go/pkg/db/retry.go (1)
  • WithRetryContext (36-46)
go/pkg/db/ratelimit_namespace_find.sql_generated.go (1)
  • FindRatelimitNamespaceRow (37-45)
go/apps/api/routes/v2_ratelimit_limit/handler.go (3)
go/apps/api/openapi/gen.go (2)
  • V2RatelimitLimitRequestBody (1785-1813)
  • V2RatelimitLimitResponseBody (1816-1821)
go/pkg/db/retry.go (1)
  • WithRetryContext (36-46)
go/pkg/db/ratelimit_namespace_find.sql_generated.go (1)
  • FindRatelimitNamespaceRow (37-45)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Build / Build
  • GitHub Check: Test Go API Local / Test
🔇 Additional comments (21)
go/internal/services/usagelimiter/limit.go (1)

16-18: Good swap to context-aware retry; keep decrement non-retried

Using db.WithRetryContext here is correct and preserves cancellation semantics. Thanks for keeping UpdateKeyCreditsDecrement outside any retry wrapper to avoid double-charging on transient failures. Based on learnings

go/internal/services/keys/get.go (1)

73-75: Context-aware DB fetch in cache loader looks good

db.WithRetryContext(ctx, …) ensures cancellation/deadline cut through the retry loop. No further changes needed.

go/internal/services/usagelimiter/redis.go (1)

241-244: Context-aware retry on DB init is correct

Switch to db.WithRetryContext(ctx, …) is appropriate; cancellation will stop backoff and avoid hanging on shutdown paths.

go/apps/api/routes/v2_ratelimit_delete_override/handler.go (2)

26-29: Type block consolidation is fine

Grouping Request/Response aliases improves readability without behavior change.


64-70: Context-aware namespace lookup

db.WithRetryContext(ctx, …) threads request ctx into retries; good alignment with the new retry API.

go/pkg/retry/retry_test.go (2)

298-389: DoContext tests cover key cancellation scenarios well

Covers pre-cancel, cancel during backoff, and deadline-exceeded with precise call counts. The ctx-aware fake sleep is a solid pattern.


391-450: DoWithResultContext semantics verified

Asserting last successful result before ctx error is great; matches wrapper behavior. Test timings/backoff align with expectations.

go/apps/api/routes/v2_ratelimit_limit/handler.go (2)

32-35: Type block consolidation looks good

No behavior change; improves readability.


78-86: Loader now respects context during retries

db.WithRetryContext(ctx, …) is the right call; cancellation will stop backoff quickly.

go/pkg/db/retry_test.go (10)

18-30: Happy-path succeeds in one call

Baseline test is clear; validates zero retry overhead.


32-48: Retries transient errors, then succeeds

Good assertion on call count and result.


65-79: Skip retry on duplicate key

Single attempt with IsDuplicateKeyError is correct.


81-95: Exhausts retries path validated

Matches default 3 attempts and error propagation.


97-123: Generic result types covered

Both int and struct cases validate type-safe usage.


125-190: Context cancellation unit tests look solid

Pre-cancel, cancel during backoff, and deadline during backoff are precisely asserted with call counts.


192-269: Integration: transient failure then success

Uses real sqlc ops; good realism and assertions.


271-307: Integration: duplicate key not retried

Correctly asserts single call and duplicate detection.


309-321: Integration: not found not retried

Good single-call assertion with IsNotFound.


322-368: Integration: cancellation halts further DB ops

Strong check that second insert never runs after cancel; good guard against post-cancel side effects.

go/pkg/db/retry.go (1)

36-45: Wiring to retry.DoWithResultContext is correct

The wrapper applies attempts/backoff/shouldRetry and passes ctx through; aligns with the new API.

go/pkg/retry/retry.go (1)

239-250: LGTM: DoWithResultContext mirrors DoContext semantics and returns last result.

Implementation is correct and consistent with DoWithResult.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 28, 2025

Thank you for following the naming conventions for pull request titles! 🙏

@vercel vercel bot temporarily deployed to Preview – engineering October 28, 2025 09:53 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 28, 2025 09:53 Inactive
Copy link
Contributor

@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: 0

🧹 Nitpick comments (1)
go/pkg/retry/retry_test.go (1)

367-374: Remove dead code: mocked sleep is never called by DoContext.

The mocked sleep function is never invoked because DoContext uses time.NewTimer with a select statement directly (lines 238-246 in retry.go) rather than calling r.sleep(). This mock is dead code and could confuse future maintainers.

Consider removing this mock:

-		// Use fake sleep that respects context cancellation
-		tt.retry.sleep = func(d time.Duration) {
-			select {
-			case <-ctx.Done():
-				return
-			case <-time.After(d):
-				return
-			}
-		}
-
 		if tt.cancelAfter > 0 {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e82d178 and c9e4091.

📒 Files selected for processing (2)
  • go/pkg/retry/retry.go (2 hunks)
  • go/pkg/retry/retry_test.go (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
go/pkg/retry/retry_test.go (1)
go/pkg/retry/retry.go (4)
  • New (65-76)
  • Attempts (83-88)
  • Backoff (93-98)
  • DoWithResultContext (255-263)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build / Build
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test API / API Test Local
  • GitHub Check: autofix
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (5)
go/pkg/retry/retry_test.go (3)

299-390: LGTM: comprehensive context cancellation test coverage.

The test cases properly cover pre-cancelled contexts, cancellation during backoff, and deadline exceeded scenarios. The tests correctly verify that context cancellation interrupts retry attempts as expected.


392-451: LGTM: DoWithResultContext correctly validates result handling.

The tests verify that partial results are returned when context is cancelled at various points in the retry sequence, ensuring result preservation across all cancellation scenarios.


453-499: LGTM: validates non-retryable context errors per requirements.

Tests confirm that context errors (both direct and wrapped) returned by fn() are treated as non-retryable and short-circuit immediately without backoff, addressing the linked issue objectives.

go/pkg/retry/retry.go (2)

203-250: LGTM: DoContext correctly implements context-aware retry semantics.

The implementation properly addresses all requirements from the linked issue and past review feedback:

  • Context checked before each attempt (lines 210-213)
  • Context errors from fn() treated as non-retryable (lines 228-230)
  • Backoff uses time.NewTimer with select to avoid memory leaks (lines 238-246)
  • Timer properly stopped on context cancellation (line 242)

255-263: LGTM: DoWithResultContext correctly captures and returns results.

The wrapper correctly delegates to DoContext while preserving the last result value, matching the behavior of the non-context DoWithResult function.

@graphite-app
Copy link

graphite-app bot commented Oct 28, 2025

TV gif. We look up at Rowan Atkinson as Mr. Bean wearing medical scrubs. He pulls down a surgical mask, gives a gloved thumbs up, and smiles maniacally. (Added via Giphy)

@Flo4604 Flo4604 added this pull request to the merge queue Oct 28, 2025
@graphite-app
Copy link

graphite-app bot commented Oct 28, 2025

Graphite Automations

"Post a GIF when PR approved" took an action on this PR • (10/28/25)

1 gif was posted to this PR based on Andreas Thomas's automation.

Merged via the queue into main with commit f399555 Oct 28, 2025
18 checks passed
@Flo4604 Flo4604 deleted the eng-2011 branch October 28, 2025 13:30
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.

Add context-aware retry helper WithRetryContext to db package

3 participants