Skip to content

Conversation

@NathanFlurry
Copy link
Member

Problem

Client uses extensive exponential backoff in local development, which is frustrating when iterating quickly.

Solution

  • Add isLocalDev() helper in env-vars.ts:
    • Server: checks NODE_ENV !== 'production'
    • Browser: checks if hostname is localhost/127.0.0.1/::1
  • Reduce retry intervals to fixed 1s in local dev (was exponential 250ms-30s)
  • Production backoff behavior unchanged

Changes

  • rivetkit-typescript/packages/rivetkit/src/utils/env-vars.ts - new isLocalDev() helper
  • rivetkit-typescript/packages/rivetkit/src/client/actor-conn.ts - use fixed 1s retries in local dev
  • rivetkit-typescript/packages/rivetkit/src/remote-manager-driver/metadata.ts - use fixed 1s retries in local dev

- Add isLocalDev() helper that checks NODE_ENV on server, hostname on browser
- Reduce retry intervals to fixed 1s in local dev (was exponential 250ms-30s)
- Affects actor-conn.ts reconnects and metadata.ts polling
- Production backoff behavior unchanged
@claude
Copy link

claude bot commented Jan 29, 2026

Code Review: Fix Local Dev Client Retry Backoff

Overview

This PR improves the local development experience by reducing retry backoff intervals from exponential (250ms-30s) to a fixed 1s delay. The changes are well-scoped and address a real DX pain point.

Positive Aspects ✅

  1. Clear Problem & Solution: The PR description clearly articulates the issue and the fix
  2. Minimal Scope: Changes are focused and don't introduce unnecessary complexity
  3. Production Unchanged: Production backoff behavior remains untouched, reducing risk
  4. Consistent Pattern: The isLocalDev() helper is reused across both modified files

Issues & Suggestions

🔴 Critical: Environment Detection Logic Issue

Location: rivetkit-typescript/packages/rivetkit/src/utils/env-vars.ts:68-82

The isLocalDev() function has a logical flaw:

export const isLocalDev = (): boolean => {
	if (typeof window \!== "undefined") {
		const hostname = window?.location?.hostname;
		if (hostname) {
			return (
				hostname === "localhost" ||
				hostname === "127.0.0.1" ||
				hostname === "::1" ||
				hostname === "[::1]"
			);
		}
	}

	return isDev();
};

Problem: When running in a browser but hostname is undefined/null, the function falls through to isDev(), which checks NODE_ENV \!== 'production'. In a browser context, NODE_ENV is typically set at build time, so this could return true even in production if the code was bundled with NODE_ENV=development.

Recommendation:

export const isLocalDev = (): boolean => {
	if (typeof window \!== "undefined") {
		const hostname = window?.location?.hostname;
		if (hostname) {
			return (
				hostname === "localhost" ||
				hostname === "127.0.0.1" ||
				hostname === "::1" ||
				hostname === "[::1]"
			);
		}
		// In browser but no hostname - assume production
		return false;
	}

	// Server-side: check NODE_ENV
	return isDev();
};

🟡 Minor: Optional Chaining Redundancy

Location: rivetkit-typescript/packages/rivetkit/src/utils/env-vars.ts:70

const hostname = window?.location?.hostname;

The typeof window \!== "undefined" check already ensures window exists, so the optional chaining on window is redundant. However, keeping it doesn't hurt and may provide defense in depth.

🟡 Minor: IPv6 Hostname Variations

Location: rivetkit-typescript/packages/rivetkit/src/utils/env-vars.ts:72-76

Consider additional IPv6 variations that might be encountered:

  • 0:0:0:0:0:0:0:1 (expanded IPv6 localhost)
  • :: (IPv6 any address, sometimes used in dev)

However, this is probably over-engineering for a local dev detection helper. The current implementation covers the most common cases.

🟢 Code Style

The code follows TypeScript conventions well. However, per CLAUDE.md:

  • Ensure hard tabs are being used (this appears to be handled by the formatter)
  • The inline retry configuration objects could be extracted to constants at the module level to reduce duplication between actor-conn.ts and metadata.ts, but the current approach is acceptable for clarity

Testing Considerations

Missing Test Coverage: There are no tests for the new isLocalDev() function. Consider adding tests for:

  1. Server-side detection (NODE_ENV checks)
  2. Browser-side detection with various hostnames
  3. Edge cases (undefined hostname, IPv6 variations)

Manual Testing Checklist:

  • Verify retry behavior in local dev (should be 1s fixed)
  • Verify retry behavior in production (should be exponential)
  • Test in browser on localhost
  • Test in browser on 127.0.0.1
  • Test server-side (Node.js runtime)

Performance & Security

Performance: ✅ No concerns. The isLocalDev() check is O(1) and only runs during retry configuration.

Security: ✅ No security concerns. The retry timing changes don't introduce vulnerabilities.

Recommendations Summary

  1. Fix the critical logic issue in isLocalDev() to explicitly return false when in browser context without a hostname
  2. Consider adding unit tests for the new isLocalDev() helper
  3. Optional: Extract retry configuration constants to reduce duplication

Verdict

The PR addresses a real DX issue with a pragmatic solution. With the critical logic fix applied, this is ready to merge. The changes are low-risk since they only affect local development behavior.

Suggested Action: Request changes to fix the isLocalDev() logic issue, then approve.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 29, 2026

More templates

@rivetkit/cloudflare-workers

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/cloudflare-workers@4062

@rivetkit/db

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/db@4062

@rivetkit/framework-base

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/framework-base@4062

@rivetkit/next-js

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/next-js@4062

@rivetkit/react

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/react@4062

rivetkit

pnpm add https://pkg.pr.new/rivet-dev/rivet/rivetkit@4062

@rivetkit/sql-loader

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/sql-loader@4062

@rivetkit/virtual-websocket

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/virtual-websocket@4062

@rivetkit/engine-runner

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner@4062

@rivetkit/engine-runner-protocol

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner-protocol@4062

commit: 744b7ae

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