From 59d958ba5eff9204eefc11592ad423593bbae302 Mon Sep 17 00:00:00 2001 From: BrightChing Date: Mon, 17 Feb 2025 10:06:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(infrastructure):=20=E6=B7=BB=E5=8A=A0=20RA?= =?UTF-8?q?GFlow=20=E5=BA=94=E7=94=A8=E7=9A=84=20Docker=20=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 .env 文件,包含 Docker 部署所需的环境变量 - 新增 README.md 文件,提供 Docker 部署的说明和配置指南 - 新增 docker-compose-base.yml 和 docker-compose.yml 文件,定义 RAGFlow 应用的 Docker 服务 - 新增 entrypoint-parser.sh 和 entrypoint.sh 脚本 --- apps/ragflow/1.0.0/.env | 140 +++++++++++++++ apps/ragflow/1.0.0/README.md | 165 ++++++++++++++++++ apps/ragflow/1.0.0/docker-compose-base.yml | 146 ++++++++++++++++ apps/ragflow/1.0.0/docker-compose.yml | 53 ++++++ apps/ragflow/1.0.0/entrypoint-parser.sh | 28 +++ apps/ragflow/1.0.0/entrypoint.sh | 34 ++++ apps/ragflow/1.0.0/infinity_conf.toml | 66 +++++++ apps/ragflow/1.0.0/init.sql | 2 + apps/ragflow/1.0.0/launch_backend_service.sh | 103 +++++++++++ apps/ragflow/1.0.0/nginx/nginx.conf | 33 ++++ apps/ragflow/1.0.0/nginx/proxy.conf | 8 + apps/ragflow/1.0.0/nginx/ragflow.conf | 29 +++ apps/ragflow/1.0.0/service_conf.yaml.template | 76 ++++++++ apps/ragflow/README.md | 20 +++ apps/ragflow/data.yml | 19 ++ apps/ragflow/logo.png | Bin 0 -> 9558 bytes 16 files changed, 922 insertions(+) create mode 100644 apps/ragflow/1.0.0/.env create mode 100644 apps/ragflow/1.0.0/README.md create mode 100644 apps/ragflow/1.0.0/docker-compose-base.yml create mode 100644 apps/ragflow/1.0.0/docker-compose.yml create mode 100755 apps/ragflow/1.0.0/entrypoint-parser.sh create mode 100755 apps/ragflow/1.0.0/entrypoint.sh create mode 100644 apps/ragflow/1.0.0/infinity_conf.toml create mode 100644 apps/ragflow/1.0.0/init.sql create mode 100644 apps/ragflow/1.0.0/launch_backend_service.sh create mode 100644 apps/ragflow/1.0.0/nginx/nginx.conf create mode 100644 apps/ragflow/1.0.0/nginx/proxy.conf create mode 100644 apps/ragflow/1.0.0/nginx/ragflow.conf create mode 100644 apps/ragflow/1.0.0/service_conf.yaml.template create mode 100644 apps/ragflow/README.md create mode 100644 apps/ragflow/data.yml create mode 100755 apps/ragflow/logo.png diff --git a/apps/ragflow/1.0.0/.env b/apps/ragflow/1.0.0/.env new file mode 100644 index 0000000..b86e8d5 --- /dev/null +++ b/apps/ragflow/1.0.0/.env @@ -0,0 +1,140 @@ +# The type of doc engine to use. +# Available options: +# - `elasticsearch` (default) +# - `infinity` (https://github.com/infiniflow/infinity) +DOC_ENGINE=${DOC_ENGINE:-elasticsearch} + +# ------------------------------ +# docker env var for specifying vector db type at startup +# (based on the vector db type, the corresponding docker +# compose profile will be used) +# ------------------------------ +COMPOSE_PROFILES=${DOC_ENGINE} + +# The version of Elasticsearch. +STACK_VERSION=8.11.3 + +# The hostname where the Elasticsearch service is exposed +ES_HOST=es01 + +# The port used to expose the Elasticsearch service to the host machine, +# allowing EXTERNAL access to the service running inside the Docker container. +ES_PORT=1200 + +# The password for Elasticsearch. +ELASTIC_PASSWORD=infini_rag_flow + +# The port used to expose the Kibana service to the host machine, +# allowing EXTERNAL access to the service running inside the Docker container. +KIBANA_PORT=6601 +KIBANA_USER=rag_flow +KIBANA_PASSWORD=infini_rag_flow + +# The maximum amount of the memory, in bytes, that a specific Docker container can use while running. +# Update it according to the available memory in the host machine. +MEM_LIMIT=8073741824 + +# The hostname where the Infinity service is exposed +INFINITY_HOST=infinity + +# Port to expose Infinity API to the host +INFINITY_THRIFT_PORT=23817 +INFINITY_HTTP_PORT=23820 +INFINITY_PSQL_PORT=5432 + +# The password for MySQL. +MYSQL_PASSWORD=infini_rag_flow +# The hostname where the MySQL service is exposed +MYSQL_HOST=mysql +# The database of the MySQL service to use +MYSQL_DBNAME=rag_flow +# The port used to expose the MySQL service to the host machine, +# allowing EXTERNAL access to the MySQL database running inside the Docker container. +MYSQL_PORT=5455 + +# The hostname where the MinIO service is exposed +MINIO_HOST=minio +# The port used to expose the MinIO console interface to the host machine, +# allowing EXTERNAL access to the web-based console running inside the Docker container. +MINIO_CONSOLE_PORT=9001 +# The port used to expose the MinIO API service to the host machine, +# allowing EXTERNAL access to the MinIO object storage service running inside the Docker container. +MINIO_PORT=9000 +# The username for MinIO. +# When updated, you must revise the `minio.user` entry in service_conf.yaml accordingly. +MINIO_USER=rag_flow +# The password for MinIO. +# When updated, you must revise the `minio.password` entry in service_conf.yaml accordingly. +MINIO_PASSWORD=infini_rag_flow + +# The hostname where the Redis service is exposed +REDIS_HOST=redis +# The port used to expose the Redis service to the host machine, +# allowing EXTERNAL access to the Redis service running inside the Docker container. +REDIS_PORT=6379 +# The password for Redis. +REDIS_PASSWORD=infini_rag_flow + +# The port used to expose RAGFlow's HTTP API service to the host machine, +# allowing EXTERNAL access to the service running inside the Docker container. +SVR_HTTP_PORT=9380 + +# The RAGFlow Docker image to download. +# Defaults to the v0.16.0-slim edition, which is the RAGFlow Docker image without embedding models. +# RAGFLOW_IMAGE=infiniflow/ragflow:v0.16.0-slim +# +# To download the RAGFlow Docker image with embedding models, uncomment the following line instead: +RAGFLOW_IMAGE=infiniflow/ragflow:v0.16.0 +# +# The Docker image of the v0.16.0 edition includes: +# - Built-in embedding models: +# - BAAI/bge-large-zh-v1.5 +# - BAAI/bge-reranker-v2-m3 +# - maidalun1020/bce-embedding-base_v1 +# - maidalun1020/bce-reranker-base_v1 +# - Embedding models that will be downloaded once you select them in the RAGFlow UI: +# - BAAI/bge-base-en-v1.5 +# - BAAI/bge-large-en-v1.5 +# - BAAI/bge-small-en-v1.5 +# - BAAI/bge-small-zh-v1.5 +# - jinaai/jina-embeddings-v2-base-en +# - jinaai/jina-embeddings-v2-small-en +# - nomic-ai/nomic-embed-text-v1.5 +# - sentence-transformers/all-MiniLM-L6-v2 +# +# + + +# If you cannot download the RAGFlow Docker image: +# +# - For the `nightly-slim` edition, uncomment either of the following: +# RAGFLOW_IMAGE=swr.cn-north-4.myhuaweicloud.com/infiniflow/ragflow:nightly-slim +# RAGFLOW_IMAGE=registry.cn-hangzhou.aliyuncs.com/infiniflow/ragflow:nightly-slim +# +# - For the `nightly` edition, uncomment either of the following: +# RAGFLOW_IMAGE=swr.cn-north-4.myhuaweicloud.com/infiniflow/ragflow:nightly +# RAGFLOW_IMAGE=registry.cn-hangzhou.aliyuncs.com/infiniflow/ragflow:nightly + +# The local time zone. +TIMEZONE='Asia/Shanghai' + +# Uncomment the following line if you have limited access to huggingface.co: +# HF_ENDPOINT=https://hf-mirror.com + +# Optimizations for MacOS +# Uncomment the following line if your OS is MacOS: +# MACOS=1 + +# The maximum file size for each uploaded file, in bytes. +# You can uncomment this line and update the value if you wish to change the 128M file size limit +# MAX_CONTENT_LENGTH=134217728 +# After making the change, ensure you update `client_max_body_size` in nginx/nginx.conf correspondingly. + +# The log level for the RAGFlow's owned packages and imported packages. +# Available level: +# - `DEBUG` +# - `INFO` (default) +# - `WARNING` +# - `ERROR` +# For example, following line changes the log level of `ragflow.es_conn` to `DEBUG`: +# LOG_LEVELS=ragflow.es_conn=DEBUG diff --git a/apps/ragflow/1.0.0/README.md b/apps/ragflow/1.0.0/README.md new file mode 100644 index 0000000..1396aa5 --- /dev/null +++ b/apps/ragflow/1.0.0/README.md @@ -0,0 +1,165 @@ +# README + +
+📗 Table of Contents + +- 🐳 [Docker Compose](#-docker-compose) +- 🐬 [Docker environment variables](#-docker-environment-variables) +- 🐋 [Service configuration](#-service-configuration) + +
+ +## 🐳 Docker Compose + +- **docker-compose.yml** + Sets up environment for RAGFlow and its dependencies. +- **docker-compose-base.yml** + Sets up environment for RAGFlow's dependencies: Elasticsearch/[Infinity](https://github.com/infiniflow/infinity), MySQL, MinIO, and Redis. + +> [!CAUTION] +> We do not actively maintain **docker-compose-CN-oc9.yml**, **docker-compose-gpu-CN-oc9.yml**, or **docker-compose-gpu.yml**, so use them at your own risk. However, you are welcome to file a pull request to improve any of them. + +## 🐬 Docker environment variables + +The [.env](./.env) file contains important environment variables for Docker. + +### Elasticsearch + +- `STACK_VERSION` + The version of Elasticsearch. Defaults to `8.11.3` +- `ES_PORT` + The port used to expose the Elasticsearch service to the host machine, allowing **external** access to the service running inside the Docker container. Defaults to `1200`. +- `ELASTIC_PASSWORD` + The password for Elasticsearch. + +### Kibana + +- `KIBANA_PORT` + The port used to expose the Kibana service to the host machine, allowing **external** access to the service running inside the Docker container. Defaults to `6601`. +- `KIBANA_USER` + The username for Kibana. Defaults to `rag_flow`. +- `KIBANA_PASSWORD` + The password for Kibana. Defaults to `infini_rag_flow`. + +### Resource management + +- `MEM_LIMIT` + The maximum amount of the memory, in bytes, that *a specific* Docker container can use while running. Defaults to `8073741824`. + +### MySQL + +- `MYSQL_PASSWORD` + The password for MySQL. +- `MYSQL_PORT` + The port used to expose the MySQL service to the host machine, allowing **external** access to the MySQL database running inside the Docker container. Defaults to `5455`. + +### MinIO + +- `MINIO_CONSOLE_PORT` + The port used to expose the MinIO console interface to the host machine, allowing **external** access to the web-based console running inside the Docker container. Defaults to `9001` +- `MINIO_PORT` + The port used to expose the MinIO API service to the host machine, allowing **external** access to the MinIO object storage service running inside the Docker container. Defaults to `9000`. +- `MINIO_USER` + The username for MinIO. +- `MINIO_PASSWORD` + The password for MinIO. + +### Redis + +- `REDIS_PORT` + The port used to expose the Redis service to the host machine, allowing **external** access to the Redis service running inside the Docker container. Defaults to `6379`. +- `REDIS_PASSWORD` + The password for Redis. + +### RAGFlow + +- `SVR_HTTP_PORT` + The port used to expose RAGFlow's HTTP API service to the host machine, allowing **external** access to the service running inside the Docker container. Defaults to `9380`. +- `RAGFLOW-IMAGE` + The Docker image edition. Available editions: + + - `infiniflow/ragflow:v0.16.0-slim` (default): The RAGFlow Docker image without embedding models. + - `infiniflow/ragflow:v0.16.0`: The RAGFlow Docker image with embedding models including: + - Built-in embedding models: + - `BAAI/bge-large-zh-v1.5` + - `BAAI/bge-reranker-v2-m3` + - `maidalun1020/bce-embedding-base_v1` + - `maidalun1020/bce-reranker-base_v1` + - Embedding models that will be downloaded once you select them in the RAGFlow UI: + - `BAAI/bge-base-en-v1.5` + - `BAAI/bge-large-en-v1.5` + - `BAAI/bge-small-en-v1.5` + - `BAAI/bge-small-zh-v1.5` + - `jinaai/jina-embeddings-v2-base-en` + - `jinaai/jina-embeddings-v2-small-en` + - `nomic-ai/nomic-embed-text-v1.5` + - `sentence-transformers/all-MiniLM-L6-v2` + +> [!TIP] +> If you cannot download the RAGFlow Docker image, try the following mirrors. +> +> - For the `nightly-slim` edition: +> - `RAGFLOW_IMAGE=swr.cn-north-4.myhuaweicloud.com/infiniflow/ragflow:nightly-slim` or, +> - `RAGFLOW_IMAGE=registry.cn-hangzhou.aliyuncs.com/infiniflow/ragflow:nightly-slim`. +> - For the `nightly` edition: +> - `RAGFLOW_IMAGE=swr.cn-north-4.myhuaweicloud.com/infiniflow/ragflow:nightly` or, +> - `RAGFLOW_IMAGE=registry.cn-hangzhou.aliyuncs.com/infiniflow/ragflow:nightly`. + +### Timezone + +- `TIMEZONE` + The local time zone. Defaults to `'Asia/Shanghai'`. + +### Hugging Face mirror site + +- `HF_ENDPOINT` + The mirror site for huggingface.co. It is disabled by default. You can uncomment this line if you have limited access to the primary Hugging Face domain. + +### MacOS + +- `MACOS` + Optimizations for macOS. It is disabled by default. You can uncomment this line if your OS is macOS. + +### Maximum file size + +- `MAX_CONTENT_LENGTH` + The maximum file size for each uploaded file, in bytes. You can uncomment this line if you wish to change the 128M file size limit. After making the change, ensure you update `client_max_body_size` in nginx/nginx.conf correspondingly. + +## 🐋 Service configuration + +[service_conf.yaml](./service_conf.yaml) specifies the system-level configuration for RAGFlow and is used by its API server and task executor. In a dockerized setup, this file is automatically created based on the [service_conf.yaml.template](./service_conf.yaml.template) file (replacing all environment variables by their values). + +- `ragflow` + - `host`: The API server's IP address inside the Docker container. Defaults to `0.0.0.0`. + - `port`: The API server's serving port inside the Docker container. Defaults to `9380`. + +- `mysql` + - `name`: The MySQL database name. Defaults to `rag_flow`. + - `user`: The username for MySQL. + - `password`: The password for MySQL. + - `port`: The MySQL serving port inside the Docker container. Defaults to `3306`. + - `max_connections`: The maximum number of concurrent connections to the MySQL database. Defaults to `100`. + - `stale_timeout`: Timeout in seconds. + +- `minio` + - `user`: The username for MinIO. + - `password`: The password for MinIO. + - `host`: The MinIO serving IP *and* port inside the Docker container. Defaults to `minio:9000`. + +- `oauth` + The OAuth configuration for signing up or signing in to RAGFlow using a third-party account. It is disabled by default. To enable this feature, uncomment the corresponding lines in **service_conf.yaml.template**. + - `github`: The GitHub authentication settings for your application. Visit the [Github Developer Settings page](https://github.com/settings/developers) to obtain your client_id and secret_key. + +- `user_default_llm` + The default LLM to use for a new RAGFlow user. It is disabled by default. To enable this feature, uncomment the corresponding lines in **service_conf.yaml.template**. + - `factory`: The LLM supplier. Available options: + - `"OpenAI"` + - `"DeepSeek"` + - `"Moonshot"` + - `"Tongyi-Qianwen"` + - `"VolcEngine"` + - `"ZHIPU-AI"` + - `api_key`: The API key for the specified LLM. You will need to apply for your model API key online. + +> [!TIP] +> If you do not set the default LLM here, configure the default LLM on the **Settings** page in the RAGFlow UI. \ No newline at end of file diff --git a/apps/ragflow/1.0.0/docker-compose-base.yml b/apps/ragflow/1.0.0/docker-compose-base.yml new file mode 100644 index 0000000..93804d5 --- /dev/null +++ b/apps/ragflow/1.0.0/docker-compose-base.yml @@ -0,0 +1,146 @@ +services: + es01: + container_name: ragflow-es-01 + profiles: + - elasticsearch + image: elasticsearch:${STACK_VERSION} + volumes: + - esdata01:/usr/share/elasticsearch/data + ports: + - ${ES_PORT}:9200 + env_file: .env + environment: + - node.name=es01 + - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} + - bootstrap.memory_lock=false + - discovery.type=single-node + - xpack.security.enabled=true + - xpack.security.http.ssl.enabled=false + - xpack.security.transport.ssl.enabled=false + - cluster.routing.allocation.disk.watermark.low=5gb + - cluster.routing.allocation.disk.watermark.high=3gb + - cluster.routing.allocation.disk.watermark.flood_stage=2gb + - TZ=${TIMEZONE} + mem_limit: ${MEM_LIMIT} + ulimits: + memlock: + soft: -1 + hard: -1 + healthcheck: + test: ["CMD-SHELL", "curl http://localhost:9200"] + interval: 10s + timeout: 10s + retries: 120 + networks: + - ragflow + restart: on-failure + + infinity: + container_name: ragflow-infinity + profiles: + - infinity + image: infiniflow/infinity:v0.6.0-dev3 + volumes: + - infinity_data:/var/infinity + - ./infinity_conf.toml:/infinity_conf.toml + command: ["-f", "/infinity_conf.toml"] + ports: + - ${INFINITY_THRIFT_PORT}:23817 + - ${INFINITY_HTTP_PORT}:23820 + - ${INFINITY_PSQL_PORT}:5432 + env_file: .env + environment: + - TZ=${TIMEZONE} + mem_limit: ${MEM_LIMIT} + ulimits: + nofile: + soft: 500000 + hard: 500000 + networks: + - ragflow + healthcheck: + test: ["CMD", "curl", "http://localhost:23820/admin/node/current"] + interval: 10s + timeout: 10s + retries: 120 + restart: on-failure + + + mysql: + # mysql:5.7 linux/arm64 image is unavailable. + image: mysql:8.0.39 + container_name: ragflow-mysql + env_file: .env + environment: + - MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD} + - TZ=${TIMEZONE} + command: + --max_connections=1000 + --character-set-server=utf8mb4 + --collation-server=utf8mb4_unicode_ci + --default-authentication-plugin=mysql_native_password + --tls_version="TLSv1.2,TLSv1.3" + --init-file /data/application/init.sql + ports: + - ${MYSQL_PORT}:3306 + volumes: + - mysql_data:/var/lib/mysql + - ./init.sql:/data/application/init.sql + networks: + - ragflow + healthcheck: + test: ["CMD", "mysqladmin" ,"ping", "-uroot", "-p${MYSQL_PASSWORD}"] + interval: 10s + timeout: 10s + retries: 3 + restart: on-failure + + minio: + image: quay.io/minio/minio:RELEASE.2023-12-20T01-00-02Z + container_name: ragflow-minio + command: server --console-address ":9001" /data + ports: + - ${MINIO_PORT}:9000 + - ${MINIO_CONSOLE_PORT}:9001 + env_file: .env + environment: + - MINIO_ROOT_USER=${MINIO_USER} + - MINIO_ROOT_PASSWORD=${MINIO_PASSWORD} + - TZ=${TIMEZONE} + volumes: + - minio_data:/data + networks: + - ragflow + restart: on-failure + + redis: + # swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/valkey/valkey:8 + image: valkey/valkey:8 + container_name: ragflow-redis + command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 128mb --maxmemory-policy allkeys-lru + env_file: .env + ports: + - ${REDIS_PORT}:6379 + volumes: + - redis_data:/data + networks: + - ragflow + restart: on-failure + + + +volumes: + esdata01: + driver: local + infinity_data: + driver: local + mysql_data: + driver: local + minio_data: + driver: local + redis_data: + driver: local + +networks: + ragflow: + driver: bridge diff --git a/apps/ragflow/1.0.0/docker-compose.yml b/apps/ragflow/1.0.0/docker-compose.yml new file mode 100644 index 0000000..676f167 --- /dev/null +++ b/apps/ragflow/1.0.0/docker-compose.yml @@ -0,0 +1,53 @@ +include: + - ./docker-compose-base.yml + +services: + ragflow: + depends_on: + mysql: + condition: service_healthy + image: ${RAGFLOW_IMAGE} + container_name: ragflow-server + ports: + - ${SVR_HTTP_PORT}:9380 + - 80:80 + - 443:443 + volumes: + - ./ragflow-logs:/ragflow/logs + - ./nginx/ragflow.conf:/etc/nginx/conf.d/ragflow.conf + - ./nginx/proxy.conf:/etc/nginx/proxy.conf + - ./nginx/nginx.conf:/etc/nginx/nginx.conf + env_file: .env + environment: + - TZ=${TIMEZONE} + - HF_ENDPOINT=${HF_ENDPOINT} + - MACOS=${MACOS} + networks: + - ragflow + restart: on-failure + # https://docs.docker.com/engine/daemon/prometheus/#create-a-prometheus-configuration + # If you're using Docker Desktop, the --add-host flag is optional. This flag makes sure that the host's internal IP gets exposed to the Prometheus container. + extra_hosts: + - "host.docker.internal:host-gateway" + # executor: + # depends_on: + # mysql: + # condition: service_healthy + # image: ${RAGFLOW_IMAGE} + # container_name: ragflow-executor + # volumes: + # - ./ragflow-logs:/ragflow/logs + # - ./nginx/ragflow.conf:/etc/nginx/conf.d/ragflow.conf + # env_file: .env + # environment: + # - TZ=${TIMEZONE} + # - HF_ENDPOINT=${HF_ENDPOINT} + # - MACOS=${MACOS} + # entrypoint: "/ragflow/entrypoint_task_executor.sh 1 3" + # networks: + # - ragflow + # restart: on-failure + # # https://docs.docker.com/engine/daemon/prometheus/#create-a-prometheus-configuration + # # If you're using Docker Desktop, the --add-host flag is optional. This flag makes sure that the host's internal IP gets exposed to the Prometheus container. + # extra_hosts: + # - "host.docker.internal:host-gateway" diff --git a/apps/ragflow/1.0.0/entrypoint-parser.sh b/apps/ragflow/1.0.0/entrypoint-parser.sh new file mode 100755 index 0000000..899f16f --- /dev/null +++ b/apps/ragflow/1.0.0/entrypoint-parser.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# replace env variables in the service_conf.yaml file +rm -rf /ragflow/conf/service_conf.yaml +while IFS= read -r line || [[ -n "$line" ]]; do + # Use eval to interpret the variable with default values + eval "echo \"$line\"" >> /ragflow/conf/service_conf.yaml +done < /ragflow/conf/service_conf.yaml.template + +export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/ + +PY=python3 + +CONSUMER_NO_BEG=$1 +CONSUMER_NO_END=$2 + +function task_exe(){ + while [ 1 -eq 1 ]; do + $PY rag/svr/task_executor.py $1; + done +} + +for ((i=CONSUMER_NO_BEG; i> /ragflow/conf/service_conf.yaml +done < /ragflow/conf/service_conf.yaml.template + +/usr/sbin/nginx + +export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/ + +PY=python3 +if [[ -z "$WS" || $WS -lt 1 ]]; then + WS=1 +fi + +function task_exe(){ + while [ 1 -eq 1 ];do + $PY rag/svr/task_executor.py $1; + done +} + +for ((i=0;i/dev/null; then + echo "Killing process $pid" + kill "$pid" + fi + done + exit 0 +} + +# Trap SIGINT and SIGTERM to invoke cleanup +trap cleanup SIGINT SIGTERM + +# Function to execute task_executor with retry logic +task_exe(){ + local task_id=$1 + local retry_count=0 + while ! $STOP && [ $retry_count -lt $MAX_RETRIES ]; do + echo "Starting task_executor.py for task $task_id (Attempt $((retry_count+1)))" + $PY rag/svr/task_executor.py "$task_id" + EXIT_CODE=$? + if [ $EXIT_CODE -eq 0 ]; then + echo "task_executor.py for task $task_id exited successfully." + break + else + echo "task_executor.py for task $task_id failed with exit code $EXIT_CODE. Retrying..." >&2 + retry_count=$((retry_count + 1)) + sleep 2 + fi + done + + if [ $retry_count -ge $MAX_RETRIES ]; then + echo "task_executor.py for task $task_id failed after $MAX_RETRIES attempts. Exiting..." >&2 + cleanup + fi +} + +# Function to execute ragflow_server with retry logic +run_server(){ + local retry_count=0 + while ! $STOP && [ $retry_count -lt $MAX_RETRIES ]; do + echo "Starting ragflow_server.py (Attempt $((retry_count+1)))" + $PY api/ragflow_server.py + EXIT_CODE=$? + if [ $EXIT_CODE -eq 0 ]; then + echo "ragflow_server.py exited successfully." + break + else + echo "ragflow_server.py failed with exit code $EXIT_CODE. Retrying..." >&2 + retry_count=$((retry_count + 1)) + sleep 2 + fi + done + + if [ $retry_count -ge $MAX_RETRIES ]; then + echo "ragflow_server.py failed after $MAX_RETRIES attempts. Exiting..." >&2 + cleanup + fi +} + +# Start task executors +for ((i=0;i? zE;d9Ff5SEnEYd&w^siN4^*dDQw9TlzOy&PqxkK6?RYbsYQ6OHyvsd%V(ZdPf^~vrWr$O#aBPgtM7jbiu?-UN{W|bn#AH#omzFll6oVsXf2|GJK z&hlS8Y36-H1u*3f$*Zj%oGZ0%%UTKl_M{tgNLOi_Rw0p_mYJn>`ZHAg$l6*cLW?%$|_u*kt(=1GoRuiT%4iW3lriMm0Lb`s)P z06F{J2v^=N)?lH`9yRCGnsz_r~#SQAickO4!V!WuD=P0KP{sX ze*eD2=bUwP>eWB})J%_$q$wN3JjUu5QEVOXafOM)=X+$obXzd5GLRvLO0g||KalcX}?=%&eL?=>ng0)>5gMcZX2 zL?W8iB3Se3!?&xJFk92Kuj+`ju) zpMzU!Ql(~HBM^k00O|pITBqvQAIT0RcWpVUdGeIdU$xpoW;KY1N%6lPx)tw%Rx(t9 zltpL|8fK5_NFSqgSCriY*gcj_GwSs4JY>1Y z?J}L`)5jFakN^!UigQSp*r1YY!R(+^K;rsWrHd^f&QcnIBVp&K*Ly_&<+zqn{x+aT zU21-B1AC}XbRAcUOe-SxaK0pd{g)IE;EE=wVYBD*lcpFaIKhB>tBHP+rlAcSpG3z( z6?EAVyy6o59o%N^txG5ML+PXJ)GBjLWsEiXn&D%Gn{&5cx&WCGUJFZ~V${6`jw5@c z+N>(TgnN)q)MuHmzKj~t=z1!W+=Qe+0s4re`YD6c{_6rAM9_E=9oE=!0%Jt&oc2M5C-z9 z&+C_++2Empp+AL&E~0N3NJPUQY9mJ?TqgD_F!b81)#kGiz7M|R+6#Yrt8N`;q{Olg z7Bcf)@7t2h4*@wHX6dxNWBLJE2(70FlWtmfK9{x>lL>T}=Poz1jk)95_I?*)`|CO1 z_oW>kK#UWph+6-1#={MM!BgUeAp>|SL1LJY%(9^=Zf>$Yan@Mdt+I~5h?(m-X-#LN zqR^&xzN?j_{9*IWR-u8Bp1R#zxv|*;Wt`erHIJV&{M2Q^J+52p9t%>#=Y%!+C54Y+ ze-;~IWYc)o6#*ZzXC-w}8>SmDNQ!^Y-yR6gswStY!&1zXz6ouE{)TCiHFfcFNT z)G?r>wL1Y?p)M0)PyXk*Gg{aUm+Zm#cp z)mIGN>eJTSF9r(Zpoz)1DS#M_SS@P#D$SfaZ22iN&T651vTgE=zn?>rZ_eOiwT48G zwl=T7lB3b$EfoLuS@Gs{pd4OV74+6WAQC4jV8XTRG#roHA6_@xlHoRSh>vqK%4&n( z7NK3%IdAF)R}Xl4_CvM<#5Q6Vx&3N;zT;A3QQSeRx5B&IIbF7o78-&7`Q?}_k=yFI zPm%6Z!ui=_&N=dR2O=zr`2Hijdf&sjQw=n;hH_c<3{#b}C6C_@94rde>FL-axyEyRsjFO(`a>)uGE_L=dWE*3t}5fm}#&*{*mcl zgzAZ>G>fME@++2f!8vwVs|Fb09NglL*|R8MDs3JL$+-+LEp6On?PuqYeFt3X{E3! zukm(DRi=w$<&__I8sb*QxQlZiOLFc5JFhWCKl9EGK%<82tYEQ4r+8WajQK&NAn7;7 zZg!W!{kFITOXfmpp`CqMQ+r3H1w=*$t1DVv!=scPGjmivyk^GD4clkL+eAj)n6@d~ z)?A)&2AR=cJ_yen@!PYRRYjY7CMcK(eOJwhG^uUI#Mywjhh~qqwP~Ti2nwX^bprOL zH}H50t7y}mUh~d8B&Ls^Gt}5!e&%OXaJjl6-m-N5X3soI$QL}BNNs;;4iDs6@Hkbr z^(HFEJKS$CFjlzpldLh%%HYdUTQ!3_*?BxxbHy~+`ytnG0ohjYwp$)75-CVwL=Ut0 z=$k3cIFe6+aZ?f(#P`K|%VIT*kc_C(DOB6U{nk1f6FxsNs<8(VBfj8V9{NPpWsViZ zfgE}7S8&qlvbei1y5`pahfi92?8gUBR$%DyMEtf(gK2esuDpcmlgKmqaxI*Uh)I^; z0lw~6{;tGQObjaCJrXH>wL<;z&N$b~jDaseB%e$Ne|JCQeY^|AFyk4_GB$~5EUsfN zFH}U$DrB5mW{XQU;e95aj+`%NQ3E-Kt$g(%CzAW{G&x~5$B+5f9Q8w|>KHS>-5x{! zwM>p2#pu=l<#PeSe>Ux22DELwJQhj5Dh>bt&8Bb0(Iu!O`3DkFL~#+b+wkul|GE6OGXu z1FTM7sTW-|nlMfGI1+T$XY4fkHRmj|S{;>iVtd`fRlA(;O@F65b9}%b>T5VSE54j0 zdCK}+*f2Ovy^IrbiuG5`&nw7s!EW08jasm=NgI+Aau(nt_~KULTj0qN6nHcfBK?Ce_w8HhEk+s z2`BFEP05?Yi@y2#&b)iM?gRHE2iaI_6n$nUS*vzIP5l<*Tao6#HcRL`d6b;Wd1sfR^;5?#*k5koj^@=Txq+-!bCA4 z>@y^3WX{g)%e#x^5>BJMEPOEl*F8N)CJ&EWcaA*H&soxmTNwmp?&G(DH{{PzN)zF4 zPSv3TPtDbXujTU4P9jrrw+bERtGHcZLFD^?fI~jjAqQe6*LhRDj<$LVJB*u#GVw`? z46vOIS~OI?JM*OrYdHyEHb0xj#-mLI> zFI){hPo3niES{ZoDN`ZT?%F4<6Pq2ZC(es|+-; z_%1eF?*Fm2BHM>2b?8+Oe4zquO_&j`CLlf`5rEr1)75H+dKJjtohdr<~~u$#Yj4l zeQ+QU$j2VRSQ9Y~=7wdb)msiSM{JT?FMMM@3>G#ulAv)R4&Iy~J=xxVktRA{e<$C| zI!0Eu{X-k1?JSH_m2#p(`+jTWlb_F9=Rqh5!t;(qoE-Wkw-umx*nwTGh4EUmFPQe;C+UtM>e z`!a#w;Bg=|W#(_xBUN)3L_1hwlDwh+)Z?BpCW@qQwCU?Fq1jDEz)^hbNkD$V$;D>b zq!nM-ntU-^a0{CWQN1L`{v#;4k{wmJ$4`;j)~+S#-L;*cikhzT}+Ge@H|LG*eYaf+3ETKj>Ycnn?BZ5kl1rP z+It2`6#)L-FzbJu}Zt2_rWoS%=w0St7o*vHGtL8m8X#p79ye;{waox~iLd z`9>vU4J^^v^1P$YepF4N--*xWyUCxu|I&IgR~_;rn_GQ^t#QrBM&1wS>+Bu5hOAn! zmDFGWYp)kQYb&vAWB2%qHvK?fWy8j7(5GZNr)M_=rGpt1GR(#uPx=7g#${XSwz4z8 z$>%6#SL3wCsmoctb*ID>G9Ds)YNw4m`*F zBqP-!;+kt}Zip7c=8hWW*n%}e`g;uhZ?mnvzp-#gYCfk6s=5f>?zaaEZ6*o{=h~ji zMYl>m6&{XfKQ&XEN79dc_&hX}sz<(@$*sSOGC8w>%P4BRSt>G~!H2RY8!>|kyN|qW zm!h`3J+9gqfP)lIWPEcN946cUGwVT?OWX$G;=WCaLnG6Gij3Qde>!yZeXvN!rox2z zh$C~Ho}Cdm9^JzLg8`MLPY)IZ)OFafHgGhYL>yUe1J_x96%#+)0QGCH`GKSOx{^=p z-`MW?X?u7^0BWp?v3#&r1X+(j1h@II5?LkwKi<&RuxRAk5Lu!xUzcwKs>jK}nKLN_ z>fUYj5r(N5uP#=h7)Rf!^X}OqDv_#XY$%N(Z7HHP+!#N^6HWy6KShZ#zQ&$^%P%twO$Q$sV`=e%0C<{aW{Z z$-4cGzU}ff2xj+>Xu7LJ)(=)J8YZ{-%zAw$Xmz!~6uoi!G8=0}op56cX&2R{oIIjk zh>{+}(R-w$klD)BAKLnJP`FU_LK9#m&ZtC%JNCHphspx}HYpRP?9K!%PRvOI~D#ifX7{#J;VfEb-Jf4o1t@T<3ci2QK_aq~)G3m%CmB^*= z%QrtiGdrUHzN$U>BKq=+=-`m4X&P7x{8ej5JK_Mqa~Bc;_h~MLU!$f@KjhxJEBcFZ z4KhrX&`A)}q0_$kEi&oLZxa$f=D42vd@z>UKgz(Z>uSNR`DgvqR+)C({Y5=UN7!Bl z^LzP+>dQoHl-DNP<{aczyl3P-Y9;&~~m-EvBU7rsf=Tj5% zwvOB#JPK>U29`>LU&opv?UO8A54@A8**re@4d3dPl-?A1&A;toPW=VP!toplaHF%L zTAVx}6QRo$K4FtcICKmh>1b%lObOm1CgacX|K@r1{<8^}K%j>hZ8=+NzIZZY{xy|! zL@R3&E2uu2C-v#2pCHILd0OP*jajz3w?iv=oqxO8tmb+RfMxPskG84~lj3L%14S?) z&8H!}-unV%n>AUaplxgjRWd0R95 zM5xJ8U(ZTYHdeAQxdXnHR)h9!dO4tI<8Al zOh$YDT?(}o5J#E7FIknPzHM7o=IX_|>#3o%H8zZ5aUyj2TKdMjpeAGl;Ni)_6zTD` z)yz@Gz|=$}*N~k`QeB@>Tec@MG()wye83-$)uUdk4sYF^tMOM9?tTjwDtWs$v)i91 zf`GpGZo4>;;OuJus z=r#9(tcZS9!ff*>MX=^$mabbou@^)daFhyZiJm^@*{ht)dysw3^RW7zr14|LEqgcTYGC43Ekpgdt@c_ zf08_f;=p|b(1D^x=Z%Cp0r&HXovysF!inDGEIhrBmdmP9F_U>uX*4*!lotb*O}Xq8 zLWFZPCJQuq<}`-=>xDcez>7;^{cqow=xdL9+uMuIbE&`%mSf0OB8go)!n!t&w`@B{ zt9O}&V`%8? zR{`3f-C0n>I5q8=Jrc48>Sd|MASZU<)7hv7crsN_%*4Np;$f>j8o$Do|iBt^d7O_<$0 z^{;j+a2y?>)@jyj6o~U{vz!ZY@h`s80cy5xD|-R2c(dtR4G>MU^IiVKa`&jiX68|Y z)kxd)hmL;?_M#T-hmObsK9`;U$(+RyD-hUlk_d$p_@J`c?AHbF&k#lpeb6?aIO^(Q zkiaCVY`4N4P@O8SE8`L_AkqYN~gVScij=@#4NJ)3#In&CT3 zVNqFhziqd8p*$Mp?xg&z=WF}MRBg}bVIS!TBXe+s3tz1b6@SVSas(E7(y)88Z{ldk zh?OCV9Rk3<9Ar(j1((eSB|=uUX^?}6riE19hggWdg1|lP0bxY;nvZAfCT`o`2 z!1#ke`UfjH<}7Lf5z&v*JFl_Xzaf7opC-@>gj6CIg^Hfw9 zRN?Yt_{L29Z$qka5yMQkp1(5>K85@7ECqzexI{MuAo*o|h!PE9uico{!}i z4Uxqy4fyK0y&MzvDK8LR?4oth2~)Gj+wb#AN%LZxCR=T39w_s>y%g9f!vyVJyxp5j z^Z}eqIXA}@3JlpF7_-4qzJ3_;mkO;wq%KVraEYZBg#(G&^!zRQC8 zVFVdRm)xb4{M5&Ktub=VRR3c*6>T{RQa0$lXZhZ2L9cL=riq2K$%&{k`N*v{#+n03 zpn|UDBUzBp?NdMlQIkk7pkz!{VutaCz6mXRze$3pnUw)<&U5qvajY6}etzK{6;Vn; zbx|Rnm-)#?k$H0JNkzlH^r>rk-NPP9-ZSCX)W)${fGF~HkY2l}t5viNBz~t5jbIpb zd<-SUW>0(`^PD5WFoD5^Gv`K!DIEPU^3vcu3`4c$-(Zqc`Hc>)en}VkHuEv_MhFEe zM+3ukWpQ%Suv{)9S%iUfFWA8i)_=Uv`w9S8dFa-X1w=mfnfzT(d%6C5#f`2e<9fIXNxH8L6 zorsW#{UX>(U{6s!-hY}$L&NE+yxzR^B_5lHdj&6{A>}jD=>86#47>r0MCF>95A)Rf zy^^b6D79b)uPf>g&C1!_2^-C;Yuh-B;Z;2iV)fy9(jbznz21M1f}$hn{Sp(~vr_gL zj%julg$;l33n2_{fxw3~`k^@y(l2zc3TMeL5$uJ8g)Ed(_uENB%l&L z*Ul;wSZo^VwsqS(ecTE4L)8=40n#s;e+wXTB zr%Xdn;eb;XG>=(IY^Cy&bt~^n>sruX0ty1H>*rkF;_MF0o8Z3GV{4C zw^YyX$FoOeh>QrY)dfVF^TtNJ#0KRkR~wq`nt#RO53!ta_D1zdI`5v9b!k9!4}Jor zbN5Q;++C^E9g};feFNi!!i|RMIcheuu(qGm;?0tXf5un;VRPQSC~H>C=ZgcFRY(;1 zW$!;w+qI~iL}bbLm6iJ%(i_%XIZTAH4OJAv!mvb$7HDRGzlO9J9LnbV3xU!Y;a}4y zIiWh!;#v+LHZ|c7{!hKe{_=jORmvVix=M<;V@&pt=k}Mh8Z_DMr^?O6x8Ky&&!MuV zlU95-TRf+FNXCyphT4fFZ(0mF@JuId{7u2B^C z@Ao=W{=J_DuBOQ(_axZ#*H%tut3+5Ex(ga03jF1hdpK(R(*@>4vIvXFGHrtOC8p$( z^RyZ!#)FJ+QILs-yjo&1Sz{?g{yU}?GzJlrk!7j|>*p7RkT811yP=ziBFQ9L-TTnZ z^(;0NfpD8@RF8{HUTNb@s8RLD5{Q&(&A!CV|G0GQXhiWIX3w&_3D4?kNDcO! z+o{)2{A4-Y`11@asOC}XE4fg0kAxjJdqXxXqt(F|tbb%Au^zlTf)i_Jmtd+Gyzr`V z#p}3HilCJ&Gy5swwpNR7=oHu^dU}ECrkv@^e>}eWcc-bCl0B;R%ko=-p-*P7nd-)_ z^(ErPG7eH}*5@V61*HS6@s-?)i}(_~m%`b<7}1Vo=K@D!tp&-D9xe9 zsU+B~JLp`_zbya>LKzw8Q>k5_38Z%IxsE`vP0jR=CBaM#{LGguzSn1{k635w)HsU4 z%9~{KT&qV8LFoOv%wSRPKUA#RA9dW;X;;O5CFjX)O_)xIv@YKqhAmI+eX6qvy1x1~ zXwb=YtO1fx`Ir%^k>!%^qY#)J7TSkX3GTAE6U&t`k@{^|EmoQES2q$m?ZfCPT&<;D z+)C(9Jb}WG$Jr_YL4Hdu^-VTFi=nN`V&uOyl(HIN?r}d1AH=HYSth|omdWL$+>q1P zXi*AGB6;-bs?9C;xIVc#NuemzL+t-coW9GEa_!t4D+HBYwp3GXR_SuYQ*qpOR!|@N z=#@9{49%(Vbcy$N(B~zrSs^qi4R%-FfK>eotm1&Ty?TE*r(e=9w;`tvtMmz>nY) zK6*@YiE80sls_hRbN`1pb=-G9fac5yDbEV?NmSZHq0Fld+X;%b^+9z=eHs6osROvb zLV_)#{S50&vdN({k;;32LlxrbS6f)*6(Z$QpfayB25+I4p{Wu}&ja(LmG*+E z=Px}IwWa90p&%e&C!WKN&+%nScxL+HskqUdE3WH^^+YAq--6z?KPu~h z0>F%1iPCmkNu{^Q0l6YfmkH8(DUBr9j6!1Xkt5h@OH$9p`r?)L7C$Z;?-C>cCZ{Ij zXp1FW`p%4eH~k}CI)c>JkHtAbb38C)dl|3Df%pUD`c#G(hqLjz?hwN_wvrlek%i^D z8NmxkqJ*jAZ4xJuAYeql#OSXVreNA^hIkOb!RO}3h|`2=bmDC-pb@nW{Vxr55rSU3 z6QUxV@lrKOrjzCC8?gaa+HH+4v~EXZRb!bbyxt z*suq8|DXtxgBgQZNlhFVg%V@|ab;&l;h!|^g4sr}!tg=?;OT-N9&;xySwKT_#t?5x zbUNHxl;X2MdeeMjc{bMftwSjmou6eh)^NkvK~Eg{EK<%`fH z7ojzS`V>J(M5v;8=pD3X={oUmBR&?lO;Qfv)+&lUBjiOWDa~YH`cF-m!+ER%Vth3{7n5|w3TG4yH(Xi$8+u8;b7dU!% zxcV2s7tejeRBF9f1&TNpsg;Hqxq@|Lxe2%t1f>~P5CfS25-ryyi<`dt6%ZPrc1|bV zoH(XZg)?#XpC<#M0REs5$7(UULxVOC6Kgey00SpW9httS zj80$}xl69j)2VOIE5P@r+gju7gPp@5sm0y&fHwfqSYkK5rh6m)-a^7<(gq~ygK6Gp zQE&0t(DFPG?w}FiGkx-H?WVt}hXA(F=H z^rA@O#0m1>C?#M^k;;Xae)P6hsuaNoxFZ^^4q-jHt<5x1&eZ{YNY)>!|7Q6M3L?7^ zRKGwqimAi}@cg7gD18$2(I%@*dfBVNoKU32`9?v0n(&}{xsrfVb1l>KN*utnRofe} zse&8(ASo2-xfeZiKwHu2N#1}0G?VPwZVj}of@{^RdK_Lh`Fl>t(pHV&5LWk;R+dD> z>?1iKQN;TtoK)M5Wl2o=X9waE02cOtq3JpC29J_fNVC7RAgl^W8lE+u&@+pxtxuQO z@(&RzAOU=dZIw9r)v)+zgdma{&_Ry4