Add ping command to test ping API (#12757)

### What problem does this PR solve?

As title.

### Type of change

- [x] New Feature (non-breaking change which adds functionality)

---------

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
Jin Hai
2026-01-22 00:18:29 +08:00
committed by GitHub
parent 2e2c8f6ca9
commit 89f438fe45
5 changed files with 110 additions and 55 deletions

View File

@ -16,9 +16,10 @@
import time import time
import json import json
from typing import Any, Dict, Optional, Tuple from typing import Any, Dict, Optional
import requests import requests
# from requests.sessions import HTTPAdapter
class HttpClient: class HttpClient:
@ -85,42 +86,46 @@ class HttpClient:
) -> requests.Response | dict: ) -> requests.Response | dict:
url = self.build_url(path, use_api_base=use_api_base) url = self.build_url(path, use_api_base=use_api_base)
merged_headers = self._headers(auth_kind, headers) merged_headers = self._headers(auth_kind, headers)
timeout: Tuple[float, float] = (self.connect_timeout, self.read_timeout) # timeout: Tuple[float, float] = (self.connect_timeout, self.read_timeout)
session = requests.Session()
# adapter = HTTPAdapter(pool_connections=100, pool_maxsize=100)
# session.mount("http://", adapter)
if iterations > 1: if iterations > 1:
response_list = [] response_list = []
total_duration = 0.0 total_duration = 0.0
for _ in range(iterations): for _ in range(iterations):
start_time = time.perf_counter() start_time = time.perf_counter()
response = requests.request( response = session.get(url, headers=merged_headers, json=json_body, data=data, stream=stream)
method=method, # response = requests.request(
url=url, # method=method,
headers=merged_headers, # url=url,
json=json_body, # headers=merged_headers,
data=data, # json=json_body,
files=files, # data=data,
params=params, # files=files,
timeout=timeout, # params=params,
stream=stream, # timeout=timeout,
verify=self.verify_ssl, # stream=stream,
) # verify=self.verify_ssl,
# )
end_time = time.perf_counter() end_time = time.perf_counter()
total_duration += end_time - start_time total_duration += end_time - start_time
response_list.append(response) response_list.append(response)
return {"duration": total_duration, "response_list": response_list} return {"duration": total_duration, "response_list": response_list}
else: else:
return requests.request( return session.get(url, headers=merged_headers, json=json_body, data=data, stream=stream)
method=method, # return requests.request(
url=url, # method=method,
headers=merged_headers, # url=url,
json=json_body, # headers=merged_headers,
data=data, # json=json_body,
files=files, # data=data,
params=params, # files=files,
timeout=timeout, # params=params,
stream=stream, # timeout=timeout,
verify=self.verify_ssl, # stream=stream,
) # verify=self.verify_ssl,
# )
def request_json( def request_json(
self, self,

View File

@ -21,7 +21,9 @@ start: command
command: sql_command | meta_command command: sql_command | meta_command
sql_command: list_services sql_command: login_user
| ping_server
| list_services
| show_service | show_service
| startup_service | startup_service
| shutdown_service | shutdown_service
@ -98,6 +100,7 @@ meta_arg: /[^\\s"']+/ | quoted_string
// command definition // command definition
LOGIN: "LOGIN"i
REGISTER: "REGISTER"i REGISTER: "REGISTER"i
LIST: "LIST"i LIST: "LIST"i
SERVICES: "SERVICES"i SERVICES: "SERVICES"i
@ -166,7 +169,9 @@ TTS: "TTS"i
ASYNC: "ASYNC"i ASYNC: "ASYNC"i
SYNC: "SYNC"i SYNC: "SYNC"i
BENCHMARK: "BENCHMARK"i BENCHMARK: "BENCHMARK"i
PING: "PING"i
login_user: LOGIN USER quoted_string ";"
list_services: LIST SERVICES ";" list_services: LIST SERVICES ";"
show_service: SHOW SERVICE NUMBER ";" show_service: SHOW SERVICE NUMBER ";"
startup_service: STARTUP SERVICE NUMBER ";" startup_service: STARTUP SERVICE NUMBER ";"
@ -212,7 +217,8 @@ list_environments: LIST ENVS ";"
benchmark: BENCHMARK NUMBER NUMBER user_statement benchmark: BENCHMARK NUMBER NUMBER user_statement
user_statement: show_current_user user_statement: ping_server
| show_current_user
| create_model_provider | create_model_provider
| drop_model_provider | drop_model_provider
| set_default_llm | set_default_llm
@ -241,6 +247,7 @@ user_statement: show_current_user
| import_docs_into_dataset | import_docs_into_dataset
| search_on_datasets | search_on_datasets
ping_server: PING ";"
show_current_user: SHOW CURRENT USER ";" show_current_user: SHOW CURRENT USER ";"
create_model_provider: CREATE MODEL PROVIDER quoted_string quoted_string ";" create_model_provider: CREATE MODEL PROVIDER quoted_string quoted_string ";"
drop_model_provider: DROP MODEL PROVIDER quoted_string ";" drop_model_provider: DROP MODEL PROVIDER quoted_string ";"
@ -298,6 +305,13 @@ class RAGFlowCLITransformer(Transformer):
def command(self, items): def command(self, items):
return items[0] return items[0]
def login_user(self, items):
email = items[2].children[0].strip("'\"")
return {"type": "login_user", "email": email}
def ping_server(self, items):
return {"type": "ping_server"}
def list_services(self, items): def list_services(self, items):
result = {"type": "list_services"} result = {"type": "list_services"}
return result return result

View File

@ -54,7 +54,6 @@ class RAGFlowCLI(Cmd):
super().__init__() super().__init__()
self.parser = Lark(GRAMMAR, start="start", parser="lalr", transformer=RAGFlowCLITransformer()) self.parser = Lark(GRAMMAR, start="start", parser="lalr", transformer=RAGFlowCLITransformer())
self.command_history = [] self.command_history = []
self.is_interactive = False
self.account = "admin@ragflow.io" self.account = "admin@ragflow.io"
self.account_password: str = "admin" self.account_password: str = "admin"
self.session = requests.Session() self.session = requests.Session()
@ -212,7 +211,6 @@ class RAGFlowCLI(Cmd):
print(separator) print(separator)
def run_interactive(self, args): def run_interactive(self, args):
self.is_interactive = True
if self.verify_auth(args, single_command=False, auth=args["auth"]): if self.verify_auth(args, single_command=False, auth=args["auth"]):
print(r""" print(r"""
____ ___ ______________ ________ ____ ____ ___ ______________ ________ ____
@ -226,7 +224,6 @@ class RAGFlowCLI(Cmd):
print("RAGFlow command line interface - Type '\\?' for help, '\\q' to quit") print("RAGFlow command line interface - Type '\\?' for help, '\\q' to quit")
def run_single_command(self, args): def run_single_command(self, args):
self.is_interactive = False
if self.verify_auth(args, single_command=True, auth=args["auth"]): if self.verify_auth(args, single_command=True, auth=args["auth"]):
command = args["command"] command = args["command"]
result = self.parse_command(command) result = self.parse_command(command)
@ -272,15 +269,15 @@ class RAGFlowCLI(Cmd):
else: else:
return {"error": "Invalid command"} return {"error": "Invalid command"}
else: else:
auth = True
if username is None: if username is None:
print("Error: username (-u) is required in user mode") auth = False
return {"error": "Username required"}
return { return {
"host": parsed_args.host, "host": parsed_args.host,
"port": parsed_args.port, "port": parsed_args.port,
"type": parsed_args.type, "type": parsed_args.type,
"username": username, "username": username,
"auth": True "auth": auth
} }
except SystemExit: except SystemExit:
return {"error": "Invalid connection arguments"} return {"error": "Invalid connection arguments"}
@ -297,7 +294,7 @@ class RAGFlowCLI(Cmd):
command_dict = parsed_command command_dict = parsed_command
# print(f"Parsed command: {command_dict}") # print(f"Parsed command: {command_dict}")
run_command(self.ragflow_client, command_dict, self.is_interactive) run_command(self.ragflow_client, command_dict)
def main(): def main():

View File

@ -22,8 +22,9 @@ import urllib.parse
from pathlib import Path from pathlib import Path
from http_client import HttpClient from http_client import HttpClient
from lark import Tree from lark import Tree
from user import encrypt_password from user import encrypt_password, login_user
import getpass
import base64 import base64
from Cryptodome.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5 from Cryptodome.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Cryptodome.PublicKey import RSA from Cryptodome.PublicKey import RSA
@ -48,6 +49,31 @@ class RAGFlowClient:
self.http_client = http_client self.http_client = http_client
self.server_type = server_type self.server_type = server_type
def login_user(self, command):
email : str = command["email"]
user_password = getpass.getpass(f"password for {email}: ").strip()
try:
token = login_user(self.http_client, self.server_type, email, user_password)
self.http_client.login_token = token
print(f"Login user {email} successfully")
except Exception as e:
print(str(e))
print("Can't access server for login (connection failed)")
def ping_server(self, command):
iterations = command.get("iterations", 1)
if iterations > 1:
response = self.http_client.request("GET", "/system/ping", use_api_base=False, auth_kind="web",
iterations=iterations)
return response
else:
response = self.http_client.request("GET", "/system/ping", use_api_base=False, auth_kind="web")
if response.status_code == 200 and response.content == b"pong":
print("Server is alive")
else:
print("Server is down")
return None
def register_user(self, command): def register_user(self, command):
if self.server_type != "user": if self.server_type != "user":
print("This command is only allowed in USER mode") print("This command is only allowed in USER mode")
@ -1222,16 +1248,17 @@ class RAGFlowClient:
print(separator) print(separator)
def run_command(client: RAGFlowClient, command_dict: dict, is_interactive: bool): def run_command(client: RAGFlowClient, command_dict: dict):
command_type = command_dict["type"] command_type = command_dict["type"]
match command_type: match command_type:
case "benchmark": case "benchmark":
run_benchmark(client, command_dict, is_interactive) run_benchmark(client, command_dict)
case "login_user":
client.login_user(command_dict)
case "ping_server":
return client.ping_server(command_dict)
case "register_user": case "register_user":
if is_interactive:
print("Register user command is not supported in interactive mode")
return
client.register_user(command_dict) client.register_user(command_dict)
case "list_services": case "list_services":
client.list_services() client.list_services()
@ -1395,23 +1422,31 @@ Meta Commands:
print(help_text) print(help_text)
def run_benchmark(client: RAGFlowClient, command_dict: dict, is_interactive: bool): def run_benchmark(client: RAGFlowClient, command_dict: dict):
concurrency = command_dict.get("concurrency", 1) concurrency = command_dict.get("concurrency", 1)
iterations = command_dict.get("iterations", 1) iterations = command_dict.get("iterations", 1)
command: dict = command_dict["command"] command: dict = command_dict["command"]
command.update({"iterations": iterations}) command.update({"iterations": iterations})
command_type = command["type"]
if concurrency < 1: if concurrency < 1:
print("Concurrency must be greater than 0") print("Concurrency must be greater than 0")
return return
elif concurrency == 1: elif concurrency == 1:
result = run_command(client, command, is_interactive) result = run_command(client, command)
success_count: int = 0
response_list = result["response_list"] response_list = result["response_list"]
total_duration = result["duration"]
success_count = 0
for response in response_list: for response in response_list:
res_json = response.json() match command_type:
if response.status_code == 200 and res_json["code"] == 0: case "ping_server":
success_count += 1 if response.status_code == 200:
success_count += 1
case _:
res_json = response.json()
if response.status_code == 200 and res_json["code"] == 0:
success_count += 1
total_duration = result["duration"]
qps = iterations / total_duration if total_duration > 0 else None qps = iterations / total_duration if total_duration > 0 else None
print(f"command: {command}, Concurrency: {concurrency}, iterations: {iterations}") print(f"command: {command}, Concurrency: {concurrency}, iterations: {iterations}")
print( print(
@ -1426,8 +1461,7 @@ def run_benchmark(client: RAGFlowClient, command_dict: dict, is_interactive: boo
executor.submit( executor.submit(
run_command, run_command,
client, client,
command, command
is_interactive
): idx ): idx
for idx in range(concurrency) for idx in range(concurrency)
} }
@ -1439,9 +1473,14 @@ def run_benchmark(client: RAGFlowClient, command_dict: dict, is_interactive: boo
for result in results: for result in results:
response_list = result["response_list"] response_list = result["response_list"]
for response in response_list: for response in response_list:
res_json = response.json() match command_type:
if response.status_code == 200 and res_json["code"] == 0: case "ping_server":
success_count += 1 if response.status_code == 200:
success_count += 1
case _:
res_json = response.json()
if response.status_code == 200 and res_json["code"] == 0:
success_count += 1
total_duration = end_time - start_time total_duration = end_time - start_time
total_command_count = iterations * concurrency total_command_count = iterations * concurrency

View File

@ -178,7 +178,7 @@ def healthz():
@manager.route("/ping", methods=["GET"]) # noqa: F821 @manager.route("/ping", methods=["GET"]) # noqa: F821
def ping(): async def ping():
return "pong", 200 return "pong", 200