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!