Skip to content

bug: ML crop recommendation service has URL mismatch, no retry, and no client-side validation #456

@Pcmhacker-piro

Description

@Pcmhacker-piro

Description

The AI crop recommendation feature has three interrelated reliability issues:

  1. ML Service URL mismatch: The frontend crop recommendation service at frontend/src/services/cropRecommendationService.ts uses process.env.NEXT_PUBLIC_API_URL || "http://localhost:3001" as the base URL and sends POST requests to ${BASE_URL}/api/recommend. However, the Python ML service (ml-service/app.py) runs on port 5001, not 3001. The Node.js backend on port 3001 is expected to proxy requests to the ML service, but there is no dedicated proxy route visible in the backend routes.

  2. No request retry or fallback: If the ML service is unavailable (e.g., model not loaded, service restarting, network partition), the request fails silently with only a generic toast notification. There is no retry with exponential backoff, no cached fallback, and no degraded-mode response.

  3. No input validation: The crop recommendation page allows submitting values outside reasonable ranges (N=0, P=145, pH=14). The ML service validates server-side, but the user gets no instant client-side feedback, leading to poor recommendations and wasted API calls.

Steps to Reproduce

  1. Open the crop recommendation page
  2. Set N=0, P=0, K=0, pH=14, Temperature=50, Humidity=100, Rainfall=5000
  3. Click "Analyse" — observe no client-side validation prevents submission
  4. Stop the ML service (or change its port)
  5. Try the recommendation again — observe the request fails silently with only a vague toast message
  6. Check the network tab — observe the request goes to port 3001 with no evidence of proxying to port 5001

Expected Behavior

  • Configuration: ML service URL should be configurable as ML_SERVICE_URL env var with http://localhost:5001 as default
  • Backend proxy: Add a dedicated proxy route /api/recommend in the backend that forwards to the ML service
  • Retry logic: Failed requests should retry up to 3 times with exponential backoff (200ms, 400ms, 800ms)
  • Caching: Identical inputs should return cached results (LRU cache, TTL 5 minutes)
  • Client-side validation: Slider inputs should show instant validation feedback for out-of-range values
  • Error UI: When the ML service is down, show a dedicated error state with a retry button, not just a toast

Implementation Hints

Backend proxy route — add to backend/routes/recommendRoutes.js:

const axios = require("axios");
const ML_SERVICE_URL = process.env.ML_SERVICE_URL || "http://localhost:5001";

router.post("/recommend", async (req, res) => {
  try {
    const response = await axios.post(`${ML_SERVICE_URL}/predict`, req.body, {
      timeout: 10000,
    });
    res.json(response.data);
  } catch (err) {
    logger.error("ML Service error", { error: err.message });
    res.status(503).json({ message: "Recommendation service unavailable" });
  }
});

Frontend retry with exponential backoff (cropRecommendationService.ts):

async function getRecommendation(inputs, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await apiClient.post("/api/recommend", inputs);
      return response.data;
    } catch (err) {
      if (i === retries - 1) throw err;
      await new Promise(r => setTimeout(r, 200 * Math.pow(2, i)));
    }
  }
}

Simple in-memory cache:

const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000;

function getCached(key) {
  const entry = cache.get(key);
  if (entry && Date.now() - entry.timestamp < CACHE_TTL) return entry.data;
  cache.delete(key);
  return null;
}

Affected Files

  • backend/routes/recommendRoutes.js
  • frontend/src/services/cropRecommendationService.ts
  • frontend/src/app/crop-recommendation/page.tsx
  • ml-service/app.py

Labels

type:bug, level:intermediate, GSSoC-26

Metadata

Metadata

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions