Move REDIS to engine dir (#16006)

### What problem does this PR solve?

as title.

### Type of change

- [x] Refactoring

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
Jin Hai
2026-06-15 14:44:16 +08:00
committed by GitHub
parent bc963f8cf2
commit fcebcebe1e
18 changed files with 84 additions and 82 deletions

View File

@@ -1,4 +1,5 @@
//go:build ignore
//
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
//
@@ -25,9 +26,9 @@ import (
"net/http"
"os"
"os/signal"
"ragflow/internal/cache"
"ragflow/internal/common"
"ragflow/internal/engine"
"ragflow/internal/engine/redis"
"ragflow/internal/utility"
"syscall"
"time"
@@ -90,10 +91,10 @@ func main() {
defer engine.Close()
// Initialize Redis cache
if err := cache.Init(&cfg.Redis); err != nil {
if err := redis.Init(&cfg.Redis); err != nil {
common.Fatal("Failed to initialize Redis", zap.Error(err))
}
defer cache.Close()
defer redis.Close()
if err := engine.InitMessageQueueEngine(cfg.TaskExecutor.MessageQueueType); err != nil {
common.Error("Failed to initialize message queue engine", err)
@@ -101,7 +102,7 @@ func main() {
// Initialize server variables (runtime variables that can change during operation)
// This must be done after Cache is initialized
if err := server.InitVariables(cache.Get()); err != nil {
if err := server.InitVariables(redis.Get()); err != nil {
common.Warn("Failed to initialize server variables from Redis, using defaults", zap.String("error", err.Error()))
}

View File

@@ -1,4 +1,5 @@
//go:build ignore
//
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
//
@@ -23,6 +24,7 @@ import (
"fmt"
"os"
"os/signal"
"ragflow/internal/engine/redis"
"ragflow/internal/ingestion"
"ragflow/internal/server/local"
"ragflow/internal/service"
@@ -32,7 +34,6 @@ import (
"syscall"
"time"
"ragflow/internal/cache"
"ragflow/internal/common"
"ragflow/internal/dao"
"ragflow/internal/engine"
@@ -122,10 +123,10 @@ func main() {
defer engine.Close()
// Initialize Redis cache
if err := cache.Init(&config.Redis); err != nil {
if err := redis.Init(&config.Redis); err != nil {
common.Fatal("Failed to initialize Redis", zap.Error(err))
}
defer cache.Close()
defer redis.Close()
// Initialize storage factory
if err := storage.InitStorageFactory(); err != nil {
@@ -137,7 +138,7 @@ func main() {
}
// Initialize server variables (runtime variables from Redis)
if err := server.InitVariables(cache.Get()); err != nil {
if err := server.InitVariables(redis.Get()); err != nil {
common.Warn("Failed to initialize server variables from Redis, using defaults", zap.String("error", err.Error()))
}

View File

@@ -1,4 +1,5 @@
//go:build ignore
//
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
//
@@ -26,6 +27,7 @@ import (
"os"
"os/signal"
"ragflow/internal/common"
"ragflow/internal/engine/redis"
"ragflow/internal/server"
"ragflow/internal/server/local"
"ragflow/internal/storage"
@@ -38,7 +40,6 @@ import (
"go.uber.org/zap"
"ragflow/internal/agent/runtime"
"ragflow/internal/cache"
"ragflow/internal/dao"
"ragflow/internal/engine"
"ragflow/internal/handler"
@@ -124,10 +125,10 @@ func main() {
defer engine.Close()
// Initialize Redis cache
if err := cache.Init(&config.Redis); err != nil {
if err := redis.Init(&config.Redis); err != nil {
common.Fatal("Failed to initialize Redis", zap.Error(err))
}
defer cache.Close()
defer redis.Close()
if err := storage.InitStorageFactory(); err != nil {
common.Fatal("Failed to initialize storage factory", zap.Error(err))
@@ -139,7 +140,7 @@ func main() {
// Initialize server variables (runtime variables that can change during operation)
// This must be done after Cache is initialized
if err := server.InitVariables(cache.Get()); err != nil {
if err := server.InitVariables(redis.Get()); err != nil {
common.Warn("Failed to initialize server variables from Redis, using defaults", zap.String("error", err.Error()))
}
@@ -257,7 +258,7 @@ func startServer(config *server.Config) {
// canary operators with a 404 they could not diagnose from the client
// side. Review follow-up: keep the route hot.
var adminRuntimeSelector *runtime.Selector
if rdb := cache.Get().GetClient(); rdb != nil {
if rdb := redis.Get().GetClient(); rdb != nil {
adminRuntimeSelector = runtime.NewSelector(rdb, common.Logger)
}
adminRuntimeHandler := handler.NewAdminRuntimeHandler(adminRuntimeSelector)

View File

@@ -21,10 +21,10 @@ import (
"errors"
"fmt"
"net/http"
"ragflow/internal/cache"
"ragflow/internal/common"
"ragflow/internal/dao"
"ragflow/internal/engine"
"ragflow/internal/engine/redis"
"ragflow/internal/server"
"ragflow/internal/service"
"ragflow/internal/utility"
@@ -151,7 +151,7 @@ func (h *Handler) Login(c *gin.Context) {
return
}
secretKey, err := server.GetSecretKey(cache.Get())
secretKey, err := server.GetSecretKey(redis.Get())
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeServerError,

View File

@@ -26,11 +26,11 @@ import (
"fmt"
"net/http"
"os"
"ragflow/internal/cache"
"ragflow/internal/common"
"ragflow/internal/dao"
"ragflow/internal/engine"
"ragflow/internal/engine/elasticsearch"
"ragflow/internal/engine/redis"
"ragflow/internal/entity"
"ragflow/internal/server"
"ragflow/internal/utility"
@@ -1206,7 +1206,7 @@ func (s *Service) getMySQLStatus(name string) (map[string]interface{}, error) {
func (s *Service) getRedisInfo(name string) (map[string]interface{}, error) {
startTime := time.Now()
redisClient := cache.Get()
redisClient := redis.Get()
if redisClient == nil {
return map[string]interface{}{
"service_name": name,

View File

@@ -25,11 +25,10 @@ package canvas
import (
"context"
"errors"
redis2 "ragflow/internal/engine/redis"
"time"
"github.com/redis/go-redis/v9"
"ragflow/internal/cache"
)
// cancelKeySuffix is appended to the task id to form the Redis key.
@@ -49,7 +48,7 @@ const RequestCancelTTL = 24 * time.Hour
// a package-level variable so tests can override it with a miniredis
// client (the production path goes through cache.Get()).
var cancelClientFn = func() (*redis.Client, error) {
rc := cache.Get()
rc := redis2.Get()
if rc == nil {
return nil, errors.New("cancel: redis cache not initialized")
}

View File

@@ -25,11 +25,10 @@ package canvas
import (
"context"
"errors"
redis2 "ragflow/internal/engine/redis"
"time"
"github.com/redis/go-redis/v9"
"ragflow/internal/cache"
)
// checkpointKeyPrefix is the Redis key namespace for checkpoint payloads.
@@ -51,7 +50,7 @@ type RedisCheckPointStore struct {
// inject their own client via struct-literal construction.
func NewRedisCheckPointStore(ttl time.Duration) *RedisCheckPointStore {
var client *redis.Client
if rc := cache.Get(); rc != nil {
if rc := redis2.Get(); rc != nil {
client = rc.GetClient()
}
return &RedisCheckPointStore{client: client, ttl: ttl}

View File

@@ -26,11 +26,10 @@ package canvas
import (
"context"
"errors"
redis2 "ragflow/internal/engine/redis"
"time"
"github.com/redis/go-redis/v9"
"ragflow/internal/cache"
)
// runKeyPrefix is the Redis Hash key namespace for run metadata.
@@ -62,7 +61,7 @@ type RunTracker struct {
// construction.
func NewRunTracker(ttl time.Duration) *RunTracker {
var client *redis.Client
if rc := cache.Get(); rc != nil {
if rc := redis2.Get(); rc != nil {
client = rc.GetClient()
}
return &RunTracker{client: client, ttl: ttl}

View File

@@ -14,7 +14,7 @@
// limitations under the License.
//
package cache
package redis
import (
"context"

View File

@@ -23,12 +23,12 @@ import (
"io"
"mime/multipart"
"net/http"
"ragflow/internal/engine/redis"
"strconv"
"strings"
"github.com/gin-gonic/gin"
"ragflow/internal/cache"
"ragflow/internal/common"
"ragflow/internal/dao"
"ragflow/internal/entity"
@@ -548,10 +548,10 @@ func (h *AgentHandler) Prompts(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeSuccess,
"data": gin.H{
"task_analysis": "As an AI agent designer, your role is to engage users by understanding their objectives and creating effective agent designs. Begin by analyzing the user's request to determine the appropriate actions.",
"output_format": "For each agent you create, detail its components and explain how they collaborate to achieve the user's goal.",
"citation_guidelines": "If the agent uses external sources, cite them in the final output. Use the format: [index] document_id, which corresponds to the document identifier in the database.",
"few_shots_examples": "<example/>",
"task_analysis": "As an AI agent designer, your role is to engage users by understanding their objectives and creating effective agent designs. Begin by analyzing the user's request to determine the appropriate actions.",
"output_format": "For each agent you create, detail its components and explain how they collaborate to achieve the user's goal.",
"citation_guidelines": "If the agent uses external sources, cite them in the final output. Use the format: [index] document_id, which corresponds to the document identifier in the database.",
"few_shots_examples": "<example/>",
},
"message": "success",
})
@@ -754,14 +754,14 @@ func (h *AgentHandler) DeleteAgentSession(c *gin.Context) {
// implemented; tests that require a real LLM response are marked
// xfail in PR3.
type agentChatCompletionsRequest struct {
AgentID string `json:"agent_id"`
Query string `json:"query"`
SessionID string `json:"session_id"`
Stream bool `json:"stream"`
OpenAICompat bool `json:"openai-compatible"`
Model string `json:"model"`
Messages []map[string]interface{} `json:"messages"`
ReturnTrace bool `json:"return_trace"`
AgentID string `json:"agent_id"`
Query string `json:"query"`
SessionID string `json:"session_id"`
Stream bool `json:"stream"`
OpenAICompat bool `json:"openai-compatible"`
Model string `json:"model"`
Messages []map[string]interface{} `json:"messages"`
ReturnTrace bool `json:"return_trace"`
}
func (h *AgentHandler) AgentChatCompletions(c *gin.Context) {
@@ -844,9 +844,9 @@ func (h *AgentHandler) RerunAgent(c *gin.Context) {
return
}
var body struct {
ID string `json:"id"`
DSL map[string]interface{} `json:"dsl"`
ComponentID string `json:"component_id"`
ID string `json:"id"`
DSL map[string]interface{} `json:"dsl"`
ComponentID string `json:"component_id"`
}
if err := c.ShouldBindJSON(&body); err != nil && !errors.Is(err, io.EOF) {
jsonError(c, common.CodeArgumentError, "Invalid request: "+err.Error())
@@ -919,7 +919,7 @@ func (h *AgentHandler) GetAgentLogs(c *gin.Context) {
}
key := fmt.Sprintf("%s-%s-logs", canvasID, messageID)
payload, rerr := cache.Get().Get(key)
payload, rerr := redis.Get().Get(key)
data := map[string]interface{}{}
if rerr == nil && payload != "" {
_ = json.Unmarshal([]byte(payload), &data)
@@ -961,9 +961,9 @@ func (h *AgentHandler) GetAgentWebhookLogs(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeSuccess,
"data": gin.H{
"events": []interface{}{},
"finished": false,
"next_since_ts": 0,
"events": []interface{}{},
"finished": false,
"next_since_ts": 0,
},
"message": "success",
})

View File

@@ -20,10 +20,10 @@ import (
"errors"
"fmt"
"net/http"
"ragflow/internal/engine/redis"
"github.com/gin-gonic/gin"
"ragflow/internal/cache"
"ragflow/internal/common"
"ragflow/internal/server"
"ragflow/internal/service"
@@ -62,7 +62,7 @@ func (h *UserHandler) OAuthLogin(c *gin.Context) {
return
}
init, code, err := h.userService.OAuthLoginInitiate(channel, cache.Get())
init, code, err := h.userService.OAuthLoginInitiate(channel, redis.Get())
if err != nil {
// Mirror Python's oauth_login: the raised ValueError propagates to
// server_error_response, which replies HTTP 200 with code 100 and
@@ -116,13 +116,13 @@ func (h *UserHandler) OAuthCallback(c *gin.Context) {
frontendBase := frontendRedirectBase()
result, _, err := h.userService.OAuthCallback(c.Request.Context(), channel, queryCode, queryState, cookieState, cache.Get())
result, _, err := h.userService.OAuthCallback(c.Request.Context(), channel, queryCode, queryState, cookieState, redis.Get())
if err != nil {
c.Redirect(http.StatusFound, frontendBase+"?error="+callbackError(channel, err))
return
}
secretKey, kerr := server.GetSecretKey(cache.Get())
secretKey, kerr := server.GetSecretKey(redis.Get())
if kerr != nil {
c.Redirect(http.StatusFound, frontendBase+"?error=server_error")
return

View File

@@ -19,8 +19,8 @@ package handler
import (
"fmt"
"net/http"
"ragflow/internal/cache"
"ragflow/internal/common"
"ragflow/internal/engine/redis"
"ragflow/internal/server"
"ragflow/internal/server/local"
"ragflow/internal/utility"
@@ -78,7 +78,7 @@ func (h *UserHandler) Register(c *gin.Context) {
return
}
secretKey, err := server.GetSecretKey(cache.Get())
secretKey, err := server.GetSecretKey(redis.Get())
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeServerError,
@@ -142,7 +142,7 @@ func (h *UserHandler) Login(c *gin.Context) {
}
// Sign the access_token using itsdangerous (compatible with Python)
secretKey, err := server.GetSecretKey(cache.Get())
secretKey, err := server.GetSecretKey(redis.Get())
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeServerError,
@@ -217,7 +217,7 @@ func (h *UserHandler) LoginByEmail(c *gin.Context) {
return
}
secretKey, err := server.GetSecretKey(cache.Get())
secretKey, err := server.GetSecretKey(redis.Get())
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeServerError,
@@ -628,6 +628,7 @@ func joinStrings(values []string) string {
}
return result
}
// ---- Forgot-password flow (fixes #15282) -----------------------------
//
// Mirrors api/apps/restful_apis/user_api.py /auth/password/... endpoints.
@@ -813,7 +814,7 @@ func (h *UserHandler) ForgotResetPassword(c *gin.Context) {
return
}
secretKey, err := server.GetSecretKey(cache.Get())
secretKey, err := server.GetSecretKey(redis.Get())
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeServerError,

View File

@@ -29,12 +29,12 @@ import (
"net/http"
"net/url"
"os"
"ragflow/internal/engine/redis"
"strings"
"time"
"gorm.io/gorm"
"ragflow/internal/cache"
"ragflow/internal/common"
"ragflow/internal/dao"
"ragflow/internal/engine"
@@ -399,7 +399,7 @@ func (s *ConnectorService) StartGoogleWebOAuth(userID, source string, req *Start
return nil, common.CodeServerError, fmt.Errorf("Failed to initialize Google OAuth flow. Please verify the uploaded client configuration.")
}
redisClient := cache.Get()
redisClient := redis.Get()
if redisClient == nil {
return nil, common.CodeServerError, fmt.Errorf("Redis is not configured on the server.")
}
@@ -433,7 +433,7 @@ func (s *ConnectorService) GoogleWebOAuthCallback(source, stateID, oauthError, e
return renderGoogleWebOAuthPopup("", false, "Missing OAuth state parameter.", source)
}
redisClient := cache.Get()
redisClient := redis.Get()
if redisClient == nil {
return renderGoogleWebOAuthPopup(stateID, false, "Authorization session expired. Please restart from the main window.", source)
}
@@ -494,7 +494,7 @@ func (s *ConnectorService) PollGoogleWebOAuthResult(userID, source string, req *
return nil, common.CodeArgumentError, fmt.Errorf("required argument is missing: flow_id")
}
redisClient := cache.Get()
redisClient := redis.Get()
if redisClient == nil {
return nil, common.CodeRunning, fmt.Errorf("Authorization is still pending.")
}

View File

@@ -24,6 +24,7 @@ import (
"os"
"path/filepath"
"ragflow/internal/common"
"ragflow/internal/engine/redis"
"ragflow/internal/entity"
"ragflow/internal/storage"
"ragflow/internal/utility"
@@ -32,12 +33,12 @@ import (
"strings"
"time"
"ragflow/internal/cache"
"ragflow/internal/dao"
"ragflow/internal/engine"
"gorm.io/gorm"
"ragflow/internal/server"
"gorm.io/gorm"
)
// DocumentService document service
@@ -998,7 +999,7 @@ func (s *DocumentService) cancelDocParse(doc *entity.Document) error {
}
// Set Redis cancel signal for each task (best-effort)
redisClient := cache.Get()
redisClient := redis.Get()
for _, t := range tasks {
if redisClient != nil {
redisClient.Set(fmt.Sprintf("%s-cancel", t.ID), "x", 0)

View File

@@ -22,10 +22,10 @@ import (
"encoding/hex"
"errors"
"fmt"
"ragflow/internal/engine/redis"
"strings"
"time"
"ragflow/internal/cache"
"ragflow/internal/common"
"ragflow/internal/dao"
"ragflow/internal/entity"
@@ -70,16 +70,16 @@ const oauthStateKey = "oauth:state:"
// so the callback can perform a CSRF check that ties the state token to the
// browser that initiated the flow.
type OAuthLoginInit struct {
State string
AuthURL string
Channel string
State string
AuthURL string
Channel string
CookieMaxAge time.Duration
}
// OAuthLoginInitiate generates a state, persists it in Redis with a TTL,
// and returns the authorization URL the browser should be redirected to.
// Mirrors the body of Python's oauth_login.
func (s *UserService) OAuthLoginInitiate(channel string, redis *cache.RedisClient) (*OAuthLoginInit, common.ErrorCode, error) {
func (s *UserService) OAuthLoginInitiate(channel string, redis *redis.RedisClient) (*OAuthLoginInit, common.ErrorCode, error) {
cfg, ok := lookupOAuthConfig(channel)
if !ok {
return nil, common.CodeDataError, fmt.Errorf("%w: %s", ErrOAuthInvalidChannel, channel)
@@ -126,7 +126,7 @@ type OAuthCallbackResult struct {
// When redis is non-nil the state is also verified against and consumed
// from Redis, defending against a replay where an attacker fishes a valid
// state out of a victim's URL but does not have the cookie.
func (s *UserService) OAuthCallback(ctx context.Context, channel, code, callbackState, expectedState string, redis *cache.RedisClient) (*OAuthCallbackResult, common.ErrorCode, error) {
func (s *UserService) OAuthCallback(ctx context.Context, channel, code, callbackState, expectedState string, redis *redis.RedisClient) (*OAuthCallbackResult, common.ErrorCode, error) {
cfg, ok := lookupOAuthConfig(channel)
if !ok {
return nil, common.CodeDataError, fmt.Errorf("%w: %s", ErrOAuthInvalidChannel, channel)

View File

@@ -20,10 +20,10 @@ import (
"context"
"encoding/json"
"fmt"
"ragflow/internal/engine/redis"
"strings"
"time"
"ragflow/internal/cache"
"ragflow/internal/dao"
"ragflow/internal/engine"
"ragflow/internal/server"
@@ -226,7 +226,7 @@ func (s *SystemService) getDatabaseStatus() ComponentStatus {
func (s *SystemService) getRedisStatus() ComponentStatus {
startedAt := time.Now()
redisClient := cache.Get()
redisClient := redis.Get()
if redisClient == nil {
return ComponentStatus{
"status": "red",
@@ -250,7 +250,7 @@ func (s *SystemService) getRedisStatus() ComponentStatus {
func (s *SystemService) getTaskExecutorHeartbeats() map[string][]interface{} {
heartbeatsByExecutor := map[string][]interface{}{}
redisClient := cache.Get()
redisClient := redis.Get()
if redisClient == nil {
return heartbeatsByExecutor
}
@@ -325,7 +325,7 @@ func (s *SystemService) Healthz(ctx context.Context) (*HealthzResponse, bool) {
}
redisOK, redisMeta := timedHealthCheck(func() error {
redisClient := cache.Get()
redisClient := redis.Get()
if redisClient == nil || !redisClient.Health() {
return fmt.Errorf("redis is not healthy")
}

View File

@@ -21,13 +21,13 @@ import (
"encoding/json"
"fmt"
"ragflow/internal/common"
"ragflow/internal/engine/redis"
"sort"
"strings"
"time"
"go.uber.org/zap"
"ragflow/internal/cache"
"ragflow/internal/dao"
"ragflow/internal/engine/types"
"ragflow/internal/entity"
@@ -61,7 +61,7 @@ func GetTagsFromCache(kbIDs []string) (map[string]float64, error) {
return nil, nil
}
redisClient := cache.Get()
redisClient := redis.Get()
if redisClient == nil {
common.Warn("Redis client not available, skipping cache lookup")
return nil, nil
@@ -89,7 +89,7 @@ func SetTagsToCache(kbIDs []string, tags map[string]float64) error {
return nil
}
redisClient := cache.Get()
redisClient := redis.Get()
if redisClient == nil {
common.Warn("Redis client not available, skipping cache store")
return nil

View File

@@ -30,8 +30,8 @@ import (
"fmt"
"hash"
"os"
"ragflow/internal/cache"
"ragflow/internal/common"
"ragflow/internal/engine/redis"
"ragflow/internal/entity"
"ragflow/internal/server"
"regexp"
@@ -732,7 +732,7 @@ func defaultUserLanguage() string {
// using itsdangerous URLSafeTimedSerializer to get the actual access_token
func (s *UserService) GetUserByToken(authorization string) (*entity.User, common.ErrorCode, error) {
// Get secret key from config
secretKey, err := server.GetSecretKey(cache.Get())
secretKey, err := server.GetSecretKey(redis.Get())
if err != nil {
return nil, common.CodeUnauthorized, err
}
@@ -1206,7 +1206,7 @@ func (s *UserService) ForgotIssueCaptcha(email string) (captchaID, imageDataURL
return "", "", common.CodeServerError, err
}
captchaID = utility.GenerateToken()
if ok := cache.Get().Set(utility.CaptchaIDRedisKey(captchaID), text, 60*time.Second); !ok {
if ok := redis.Get().Set(utility.CaptchaIDRedisKey(captchaID), text, 60*time.Second); !ok {
return "", "", common.CodeServerError, fmt.Errorf("failed to store captcha")
}
imageDataURL = utility.RenderCaptchaPNGDataURL(text)
@@ -1226,7 +1226,7 @@ func (s *UserService) ForgotSendOTP(email, captchaID, captcha string) (common.Er
return common.CodeDataError, fmt.Errorf("invalid email")
}
rc := cache.Get()
rc := redis.Get()
captchaKey := utility.CaptchaIDRedisKey(captchaID)
stored, _ := rc.Get(captchaKey)
if stored == "" {
@@ -1325,7 +1325,7 @@ func (s *UserService) ForgotVerifyOTP(email, otp string) (common.ErrorCode, erro
return common.CodeDataError, fmt.Errorf("invalid email")
}
rc := cache.Get()
rc := redis.Get()
codeKey, attemptsKey, lastSentKey, lockKey := utility.OTPRedisKeys(email)
if locked, _ := rc.Get(lockKey); locked != "" {
@@ -1395,7 +1395,7 @@ func (s *UserService) ForgotResetPassword(req *ForgotResetPasswordRequest) (*ent
return nil, common.CodeArgumentError, fmt.Errorf("email and passwords are required")
}
rc := cache.Get()
rc := redis.Get()
verifiedKey := utility.OTPVerifiedRedisKey(req.Email)
if v, _ := rc.Get(verifiedKey); v != "1" {
return nil, common.CodeAuthenticationError, fmt.Errorf("email not verified")