Skip to content

Production Performance Troubleshooting

This page contains interview-oriented troubleshooting questions and concise answers covering common production performance and compatibility issues.

1. Data Saves Successfully but Does Not Appear Until Browser Refresh

Section titled “1. Data Saves Successfully but Does Not Appear Until Browser Refresh”

Users report that data saves successfully but does not appear until they refresh the browser. How would you troubleshoot?

I would troubleshoot it layer by layer:

  1. Frontend state

    • Check whether the POST/PUT succeeds but React state is not updated.
    • Verify setState, Redux/Zustand state, or React Query cache invalidation.
    • Check for stale closures or incorrect dependency arrays.
  2. API response

    • Verify the save API returns the newly created/updated data correctly.
    • Check whether the subsequent GET request is actually triggered.
    • Inspect the Network tab for request/response timing and payloads.
  3. Caching

    • Check browser cache, CDN cache, API gateway/cache, Redis, or React Query cache.
    • Verify cache invalidation after the mutation.
  4. Backend/database

    • Confirm the transaction is committed before the GET executes.
    • Check transaction isolation, read replicas, and replication lag.
    • Ensure the GET query can see the newly saved record.
  5. Browser behavior

    • Compare normal refresh vs. hard refresh.
    • Check console errors and Network tab for failed or stale requests.
  • React state not being updated.
  • Stale API/query cache.
  • Database read-replica lag.
  • GET request not being triggered after the save.
  • Transaction visibility/commit timing issues.

“I’d trace the data flow from DB → API → browser → React state. First I’d confirm the save API and DB transaction, then inspect the GET response. If the GET has fresh data but the UI doesn’t, it’s a frontend state/cache issue. If GET itself is stale, I’d investigate API/Redis/CDN caching or database read-replica lag.”

flowchart LR
    UI[React UI] -->|POST / PUT| API[Backend API]
    API --> DB[(Database)]
    DB --> API
    API --> UI
    UI -->|Update State / Refetch| STATE[Frontend State]
    STATE --> UI
flowchart TD
    A[Save succeeds] --> B{Is API response correct?}
    B -->|No| C[Investigate backend / DB / transaction]
    B -->|Yes| D{Does GET return fresh data?}
    D -->|No| E[Investigate cache / replica lag / transaction visibility]
    D -->|Yes| F{Does UI display fresh state?}
    F -->|No| G[Investigate React state / query cache / component lifecycle]
    F -->|Yes| H[Issue resolved]

2. Application Works in Chrome but Fails in Edge

Section titled “2. Application Works in Chrome but Fails in Edge”

An application works in Chrome but fails in Edge. What steps would you take?

I would reproduce the issue in Edge and compare its behavior with Chrome.

  • Test the same URL and user flow in both browsers.
  • Use Edge DevTools.
  • Check the Console for JavaScript errors.
  • Check the Network tab for failed requests.
  • Compare request headers, payloads, status codes, and responses.

Check for:

  • Unsupported or experimental JavaScript APIs.
  • Browser-specific Web APIs.
  • CSS compatibility issues.
  • JavaScript language features that are not properly transpiled.
  • Browser-specific API usage.

Prefer feature detection over browser-specific checks.

Check:

  • Browser cache.
  • Cookies.
  • LocalStorage.
  • SessionStorage.
  • IndexedDB.
  • Service workers.
  • SameSite and Secure cookie behavior.

Also test using Edge InPrivate mode.

Investigate:

  • CORS.
  • CSP.
  • Authentication redirects.
  • Cookie restrictions.
  • Third-party cookie blocking.
  • Tracking prevention.

Check:

  • Polyfills.
  • Babel/transpilation configuration.
  • JavaScript bundle compatibility.
  • React and third-party library versions.

Compare Chrome and Edge requests:

Request URL
HTTP Method
Headers
Cookies
Payload
Status Code
Response Body
Timing

Use standards-based fixes rather than browser-specific hacks.

Test across:

  • Chrome
  • Edge
  • Firefox
  • Safari

“I’d first reproduce the issue in Edge and compare Console and Network logs with Chrome. Then I’d check browser compatibility, JavaScript/CSS features, cookies and storage, CORS/CSP, authentication, and API differences. Finally, I’d identify whether the issue is frontend, browser-specific behavior, or backend request handling and fix it using standards-based compatibility rather than a browser-specific workaround.”

flowchart TD
    A[Works in Chrome] --> B[Reproduce in Edge]
    B --> C{Console Error?}
    C -->|Yes| D[Investigate JS / CSS / API compatibility]
    C -->|No| E{Network Difference?}
    E -->|Yes| F[Compare headers / cookies / CORS / API]
    E -->|No| G{Storage or Cache Issue?}
    G -->|Yes| H[Clear cache / inspect cookies / storage]
    G -->|No| I[Check dependencies / polyfills / browser APIs]
    D --> J[Apply standards-based fix]
    F --> J
    H --> J
    I --> J

3. Memory Consumption Continues Increasing in Production

Section titled “3. Memory Consumption Continues Increasing in Production”

Memory consumption continues increasing in production. How would you identify frontend memory leaks and Java heap leaks?

The first step is to determine whether the growth is browser-side or backend JVM-side.


Use browser developer tools, especially:

  • Memory / Heap Snapshot
  • Allocation Timeline
  • Performance profiling

Take heap snapshots at different points:

Initial State
Use Application
Take Snapshot
Navigate / Repeat Operation
Force / Wait for GC
Take Snapshot Again
Compare Retained Objects

Look for objects that continue to remain retained after garbage collection.

  • Event listeners not removed.
  • setInterval() / setTimeout() not cleared.
  • WebSocket or subscription cleanup missing.
  • Large objects retained by closures.
  • React useEffect cleanup missing.
  • Unbounded browser caches.
  • Global variables retaining objects.
  • Components retaining references after unmount.
useEffect(() => {
const handler = () => {
// logic
};
window.addEventListener("resize", handler);
return () => {
window.removeEventListener("resize", handler);
};
}, []);

The cleanup function prevents the listener from remaining after the component is unmounted.

A strong indicator is:

Memory keeps growing after repeatedly mounting/unmounting a component, and garbage collection does not reclaim the previously allocated objects.


Start by monitoring JVM metrics:

  • Heap usage.
  • Old Generation usage.
  • GC frequency.
  • GC pause time.
  • Allocation rate.
  • Thread count.
  • OutOfMemoryError events.

Useful monitoring tools include:

  • Spring Boot Actuator.
  • JMX.
  • Prometheus.
  • Grafana.
  • Java Flight Recorder.
  • Eclipse MAT.
  • VisualVM.

Take heap dumps at different times and compare:

flowchart LR
    A[Production JVM] --> B[JVM Metrics]
    B --> C{Heap Continues Growing?}
    C -->|No| D[Investigate Temporary Load / Allocation Spike]
    C -->|Yes| E[Take Heap Dump]
    E --> F[Analyze Retained Objects]
    F --> G[Compare Heap Dumps]
    G --> H[Identify Growing Object Graph]
    H --> I[Find Retention Root]
    I --> J[Fix Leak]
  • Static collections/maps growing indefinitely.
  • Unbounded caches.
  • Missing cache eviction.
  • ThreadLocal values not removed.
  • Objects retained by listeners.
  • Large session objects.
  • Unbounded queues.
  • Improperly managed resources.
  • Long-lived references from singleton beans.

A strong indicator is:

After multiple GC cycles, Old Generation usage continues increasing and approaches the configured heap limit.

This can eventually lead to:

java.lang.OutOfMemoryError: Java heap space

“For frontend leaks, I’d use browser heap snapshots and allocation profiling to find objects that remain retained after GC, especially listeners, timers, subscriptions, and React effects. For Java, I’d monitor heap and GC metrics first, then take and compare heap dumps to identify objects with increasing retained size. I’d also distinguish a true memory leak from legitimate cache growth or high traffic causing increased memory usage.”

Area Frontend Java Backend
Primary Tool Browser DevTools JFR / JMX / MAT / VisualVM
Main Metric Browser heap JVM heap / Old Gen
Main Technique Heap snapshots Heap dumps
Look For Retained JS objects Retained Java objects
Common Cause Listeners, timers, effects Caches, static collections, ThreadLocal
Key Signal Memory survives GC Old Gen keeps growing after GC

4. API Response Time Doubled After Deployment

Section titled “4. API Response Time Doubled After Deployment”

After a deployment API response times doubled. How would you investigate?

I would compare before vs. after deployment and isolate where the additional latency was introduced.

Compare:

  • p50 latency.
  • p95 latency.
  • p99 latency.
  • Error rate.
  • Throughput.
  • Affected endpoints.
  • Affected service instances.

Do not rely only on average latency.

Review:

  • CPU utilization.
  • Memory utilization.
  • JVM heap.
  • GC pauses.
  • Thread-pool utilization.
  • Database connection-pool usage.
  • Request queueing.
  • Error rates.
  • Retries.
  • Timeouts.

A sudden increase in retries or thread/connection contention can significantly increase response time.

Trace a slow request through the complete request path:

flowchart LR
    C[Client] --> G[API Gateway]
    G --> S[Application Service]
    S --> DB[(Database)]
    S --> E[External Service]

Identify exactly where the latency increased.

For example:

Before Deployment
API: 200 ms
DB: 80 ms
External: 50 ms
After Deployment
API: 400 ms
DB: 80 ms
External: 200 ms

This immediately points toward the external service rather than the database.

Check:

  • Slow queries.
  • Query execution plans.
  • Missing indexes.
  • Increased query count.
  • N+1 queries.
  • Lock contention.
  • Connection-pool exhaustion.
  • Database CPU/load.

A small code change that adds a query inside a loop can cause a major performance regression.

Compare the previous and current versions for:

  • Code changes.
  • Dependencies.
  • Database queries.
  • API calls.
  • Configuration.
  • JVM settings.
  • Feature flags.
  • Cache configuration.
  • Logging configuration.

Pay particular attention to newly introduced synchronous processing or external API calls.

Investigate:

  • Kubernetes pod CPU/memory limits.
  • Pod restarts.
  • Autoscaling.
  • Load-balancer behavior.
  • Network latency.
  • Service-to-service communication.
  • Number of running instances.
  • Container throttling.

If production impact is significant:

  • Roll back the deployment, or
  • Disable the new functionality using a feature flag.

Then continue the root-cause investigation safely.

“I’d first compare p50, p95, and p99 latency before and after the deployment to confirm and quantify the regression. Then I’d use distributed tracing and application metrics to identify whether the additional latency is coming from application code, database calls, external services, or infrastructure. I’d compare the deployment changes, investigate database execution plans, GC, thread and connection pools, retries, and network latency. If the impact is significant, I’d roll back or disable the new feature while investigating the root cause.”

flowchart TD
    A[API Latency Doubled] --> B[Compare Before vs After]
    B --> C[Check p50 / p95 / p99]
    C --> D[Application Metrics]
    D --> E[Distributed Tracing]
    E --> F{Where is latency introduced?}

    F -->|Application| G[Code / CPU / GC / Threads]
    F -->|Database| H[Queries / Indexes / Locks / Pool]
    F -->|External API| I[Network / Timeout / Retry]
    F -->|Infrastructure| J[Kubernetes / LB / Network]

    G --> K[Compare Deployment Changes]
    H --> K
    I --> K
    J --> K

    K --> L{Production Impact High?}
    L -->|Yes| M[Rollback / Feature Flag]
    L -->|No| N[Fix Root Cause]
    M --> N
    N --> O[Deploy and Monitor]

Problem First Check Deep Investigation Common Root Cause
Saved data not visible API response + React state GET, cache, transaction, replica Stale state/cache
Chrome works, Edge fails Console + Network Compatibility, cookies, CORS, polyfills Browser-specific behavior
Memory continuously increases Heap metrics Heap snapshots / heap dumps Retained objects / unbounded cache
API latency doubled p95/p99 comparison Distributed tracing + DB metrics Slow query / external call / resource contention

Universal Production Troubleshooting Pattern

Section titled “Universal Production Troubleshooting Pattern”
flowchart TD
    A[Production Issue] --> B[Reproduce]
    B --> C[Measure]
    C --> D[Compare With Healthy Baseline]
    D --> E[Check Logs and Metrics]
    E --> F[Trace Request / Resource]
    F --> G[Isolate Component]
    G --> H[Form Hypothesis]
    H --> I[Test Hypothesis]
    I --> J{Confirmed?}
    J -->|No| H
    J -->|Yes| K[Fix / Mitigate]
    K --> L[Regression Test]
    L --> M[Deploy]
    M --> N[Monitor]

For production troubleshooting, avoid jumping directly to a fix.

Use:

Measure → Compare → Trace → Isolate → Hypothesize → Validate → Mitigate → Fix → Monitor

This demonstrates a structured production-debugging mindset rather than guesswork.