Performance Issues with Email Login API During Load Testing

Hi Frappe Community, @rmehta @umair @nabinhait @buildwithhussain

I’ve been working on a Next.js-based client application that interacts with Frappe ERPNext as the backend. One of the APIs, specifically the Email Login API, is facing performance issues during load testing using Apache JMeter. While all other APIs meet performance requirements, this login API fails to handle a ramp-up of 39 users per minute.

Observed Issues:

  • 28 HTTP 401 Errors: Authentication issues despite valid credentials.
  • 38 HTTP 504 Errors: Gateway timeouts when concurrent requests increase.

API Implementation Details:

The API uses the LoginManager class from Frappe’s core for authentication. Here’s the server-side implementation (simplified):

@frappe.whitelist(allow_guest=True)
def email_login(usr, pwd):
    try:
        user_details = frappe.get_doc('User', usr)
    except frappe.exceptions.DoesNotExistError:
        frappe.local.response["status_code"] = 404
        frappe.local.response["message"] = "User not Found"
        return
    try:
        login_manager.authenticate(user=usr, pwd=pwd)
        login_manager.post_login()
    except frappe.exceptions.AuthenticationError:
        frappe.log_error(message=frappe.get_traceback(), title="Email Login Error")
        frappe.local.response["status_code"] = 401
        frappe.local.response["message"] = "Invalid username/password"
        return
    except Exception as e:
        frappe.log_error(message=str(e), title="Email Login Error")
        frappe.local.response["status_code"] = 500
        frappe.local.response["message"] = str(e)
        return

    api_secret = frappe.generate_hash(length=15)
    if not user_details.api_key:
        api_key = frappe.generate_hash(length=15)
        user_details.api_key = api_key

    user_details.api_secret = api_secret
    user_details.flags.ignore_permissions = True
    user_details.flags.ignore_password_policy = True
    user_details.save()

    token = base64.b64encode(f"{user_details.api_key}:{api_secret}".encode("utf-8")).decode("utf-8")

    frappe.local.response.update({
        "status_code": 200,
        "message": "Authentication success",
        "auth_key": token,
        "email": user_details.email
    })

Frontend Details:

The Next.js frontend uses the following function to call the API:

export async function emailLogin(data) {
  const response = await fetch(`${process.env.NEXT_PUBLIC_BASEURL}api/method/lawbazar.web_api.user.email_login`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });
  const result = await response.json();

  if (!response.ok) {
    return Promise.reject(new Error(result?.message));
  }

  return result;
}

What I’ve Tried:

  • Validated API functionality under normal conditions (works fine).
  • Checked database indexing for User-related queries.
  • Confirmed correct API usage from the frontend.
  • Logged errors with frappe.log_error for traceability.

Questions for the Community:

  • Has anyone faced similar performance issues with the LoginManager?
  • What optimizations can be made in the API code or server settings to better handle concurrent requests?
  • Any tips for improving Frappe’s authentication performance under load?

Looking forward to your insights!