mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2026-02-04 07:53:11 +00:00
Optimize server rotation to use primary server first, only rotate on network errors
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
This commit is contained in:
parent
bd566cdfe5
commit
b3969d1fd7
@ -1,7 +1,7 @@
|
|||||||
import axios from "@/axios/axios";
|
import axios from "@/axios/axios";
|
||||||
import {formatResponse, formatError} from "../dataProvider";
|
import {formatResponse, formatError} from "../dataProvider";
|
||||||
import {getSetting} from "../settings";
|
import {getSetting} from "../settings";
|
||||||
import {tryWithRotation, isRotationEnabled} from "../serverRotation";
|
import {tryWithPrimaryServer, isRotationEnabled} from "../serverRotation";
|
||||||
|
|
||||||
// Helper function to get request headers with kvtoken
|
// Helper function to get request headers with kvtoken
|
||||||
const getHeaders = () => {
|
const getHeaders = () => {
|
||||||
@ -23,9 +23,9 @@ const getHeaders = () => {
|
|||||||
export const kvServerProvider = {
|
export const kvServerProvider = {
|
||||||
async loadNamespaceInfo() {
|
async loadNamespaceInfo() {
|
||||||
try {
|
try {
|
||||||
// Use rotation for classworkscloud provider
|
// Use primary server with fallback for classworkscloud provider
|
||||||
if (isRotationEnabled()) {
|
if (isRotationEnabled()) {
|
||||||
return await tryWithRotation(async (serverUrl) => {
|
return await tryWithPrimaryServer(async (serverUrl) => {
|
||||||
const res = await axios.get(`${serverUrl}/kv/_info`, {
|
const res = await axios.get(`${serverUrl}/kv/_info`, {
|
||||||
headers: getHeaders(),
|
headers: getHeaders(),
|
||||||
});
|
});
|
||||||
@ -52,9 +52,9 @@ export const kvServerProvider = {
|
|||||||
|
|
||||||
async updateNamespaceInfo(data) {
|
async updateNamespaceInfo(data) {
|
||||||
try {
|
try {
|
||||||
// Use rotation for classworkscloud provider
|
// Use primary server with fallback for classworkscloud provider
|
||||||
if (isRotationEnabled()) {
|
if (isRotationEnabled()) {
|
||||||
return await tryWithRotation(async (serverUrl) => {
|
return await tryWithPrimaryServer(async (serverUrl) => {
|
||||||
const res = await axios.put(`${serverUrl}/kv/_info`, data, {
|
const res = await axios.put(`${serverUrl}/kv/_info`, data, {
|
||||||
headers: getHeaders(),
|
headers: getHeaders(),
|
||||||
});
|
});
|
||||||
@ -78,9 +78,9 @@ export const kvServerProvider = {
|
|||||||
|
|
||||||
async loadData(key) {
|
async loadData(key) {
|
||||||
try {
|
try {
|
||||||
// Use rotation for classworkscloud provider
|
// Use primary server with fallback for classworkscloud provider
|
||||||
if (isRotationEnabled()) {
|
if (isRotationEnabled()) {
|
||||||
return await tryWithRotation(async (serverUrl) => {
|
return await tryWithPrimaryServer(async (serverUrl) => {
|
||||||
const res = await axios.get(`${serverUrl}/kv/${key}`, {
|
const res = await axios.get(`${serverUrl}/kv/${key}`, {
|
||||||
headers: getHeaders(),
|
headers: getHeaders(),
|
||||||
});
|
});
|
||||||
@ -108,9 +108,9 @@ export const kvServerProvider = {
|
|||||||
|
|
||||||
async saveData(key, data) {
|
async saveData(key, data) {
|
||||||
try {
|
try {
|
||||||
// Use rotation for classworkscloud provider
|
// Use primary server with fallback for classworkscloud provider
|
||||||
if (isRotationEnabled()) {
|
if (isRotationEnabled()) {
|
||||||
return await tryWithRotation(async (serverUrl) => {
|
return await tryWithPrimaryServer(async (serverUrl) => {
|
||||||
await axios.post(`${serverUrl}/kv/${key}`, data, {
|
await axios.post(`${serverUrl}/kv/${key}`, data, {
|
||||||
headers: getHeaders(),
|
headers: getHeaders(),
|
||||||
});
|
});
|
||||||
@ -171,9 +171,9 @@ export const kvServerProvider = {
|
|||||||
skip: skip.toString()
|
skip: skip.toString()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Use rotation for classworkscloud provider
|
// Use primary server with fallback for classworkscloud provider
|
||||||
if (isRotationEnabled()) {
|
if (isRotationEnabled()) {
|
||||||
return await tryWithRotation(async (serverUrl) => {
|
return await tryWithPrimaryServer(async (serverUrl) => {
|
||||||
const res = await axios.get(`${serverUrl}/kv/_keys?${params}`, {
|
const res = await axios.get(`${serverUrl}/kv/_keys?${params}`, {
|
||||||
headers: getHeaders(),
|
headers: getHeaders(),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,6 +11,9 @@ const CLASSWORKS_CLOUD_SERVERS = [
|
|||||||
"https://kv-service.wuyuan.dev",
|
"https://kv-service.wuyuan.dev",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Track the current primary server (the one that's currently working)
|
||||||
|
let primaryServerUrl = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of servers to try for the given provider
|
* Get the list of servers to try for the given provider
|
||||||
* @param {string} provider - The provider type
|
* @param {string} provider - The provider type
|
||||||
@ -59,6 +62,11 @@ export async function tryWithRotation(operation, options = {}) {
|
|||||||
onServerTried({ url: serverUrl, status: "success", tried: [...triedServers] });
|
onServerTried({ url: serverUrl, status: "success", tried: [...triedServers] });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update primary server on success (for classworkscloud provider)
|
||||||
|
if (provider === "classworkscloud") {
|
||||||
|
primaryServerUrl = serverUrl;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
lastError = error;
|
lastError = error;
|
||||||
@ -82,7 +90,7 @@ export async function tryWithRotation(operation, options = {}) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the effective server URL for the current provider
|
* Get the effective server URL for the current provider
|
||||||
* For classworkscloud, returns the first server in the list
|
* For classworkscloud, returns the primary server (last known working) or first server in the list
|
||||||
* For other providers, returns the configured domain
|
* For other providers, returns the configured domain
|
||||||
* @returns {string} Server URL
|
* @returns {string} Server URL
|
||||||
*/
|
*/
|
||||||
@ -90,7 +98,8 @@ export function getEffectiveServerUrl() {
|
|||||||
const provider = getSetting("server.provider");
|
const provider = getSetting("server.provider");
|
||||||
|
|
||||||
if (provider === "classworkscloud") {
|
if (provider === "classworkscloud") {
|
||||||
return CLASSWORKS_CLOUD_SERVERS[0];
|
// Return primary server if available, otherwise first in list
|
||||||
|
return primaryServerUrl || CLASSWORKS_CLOUD_SERVERS[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return getSetting("server.domain") || "";
|
return getSetting("server.domain") || "";
|
||||||
@ -104,3 +113,64 @@ export function isRotationEnabled() {
|
|||||||
const provider = getSetting("server.provider");
|
const provider = getSetting("server.provider");
|
||||||
return provider === "classworkscloud";
|
return provider === "classworkscloud";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an error is a network error that should trigger server rotation
|
||||||
|
* @param {Error} error - The error to check
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function isNetworkError(error) {
|
||||||
|
// Network errors from axios typically have no response or specific error codes
|
||||||
|
if (!error.response) {
|
||||||
|
return true; // No response = network issue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server timeout or connection errors
|
||||||
|
if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT' ||
|
||||||
|
error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5xx errors might indicate server issues worth retrying
|
||||||
|
const status = error.response?.status;
|
||||||
|
if (status >= 500) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try operation with primary server first, fallback to rotation on network errors only
|
||||||
|
* This is more efficient than always trying rotation for every request
|
||||||
|
* @param {Function} operation - Async function that takes a serverUrl and returns a promise
|
||||||
|
* @param {Object} options - Options
|
||||||
|
* @param {string} options.provider - Provider type (optional, defaults to current setting)
|
||||||
|
* @returns {Promise} Result from the operation
|
||||||
|
*/
|
||||||
|
export async function tryWithPrimaryServer(operation, options = {}) {
|
||||||
|
const provider = options.provider || getSetting("server.provider");
|
||||||
|
|
||||||
|
// For non-classworkscloud providers, just use the configured domain
|
||||||
|
if (provider !== "classworkscloud") {
|
||||||
|
const serverUrl = getSetting("server.domain");
|
||||||
|
return await operation(serverUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For classworkscloud, try primary server first
|
||||||
|
const primaryUrl = getEffectiveServerUrl();
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await operation(primaryUrl);
|
||||||
|
} catch (error) {
|
||||||
|
// Only rotate to other servers if it's a network error
|
||||||
|
if (isNetworkError(error)) {
|
||||||
|
console.warn(`Primary server ${primaryUrl} failed with network error, trying rotation...`);
|
||||||
|
// Use full rotation, which will update the primary server if a different one succeeds
|
||||||
|
return await tryWithRotation(operation, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-network errors (e.g., 404, 401, validation errors), don't retry with other servers
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user