From 11ae6761adf1fd96a6a5e9156b228cf0547d628e Mon Sep 17 00:00:00 2001 From: "Eric 1549169735@qq.com" <1549169735@qq.com> Date: Wed, 19 Aug 2026 22:19:51 +0800 Subject: [PATCH] feat: enable configured multitable synchronization --- configs/config.prod.yml | 29 +++++++++++++++++++++++++++++ configs/config.yml | 26 +++++++++++++------------- internal/config/config.go | 10 +--------- internal/config/config_test.go | 19 ++++--------------- internal/multitable/worker.go | 5 ++++- 5 files changed, 51 insertions(+), 38 deletions(-) diff --git a/configs/config.prod.yml b/configs/config.prod.yml index 98a54fb..989e6ea 100644 --- a/configs/config.prod.yml +++ b/configs/config.prod.yml @@ -3,9 +3,38 @@ app: server: host: 0.0.0.0 database: + host: taosuvet.rwlb.rds.aliyuncs.com + port: 3306 + user: taosuvet_root + password: Yong!!!2030 + name: iqudo_top1 max_idle_connections: 20 max_open_connections: 100 +auth: + jwt_secret: random-1234567890-zyxwvu-tsrpml210 + access_token_ttl: 2h + refresh_token_ttl: 168h seed: admin_username: "" admin_password: "" admin_display_name: "" +multitable: + enabled: true + base_url: https://table.iwork-ai.com/open/v1 + api_key: iqd_6dd7293ce4d50f02949fe35bea669a0b156a4143f11ed5525aafe76e2c089685 + sync_interval: 5s + request_timeout: 10s + batch_size: 20 + max_attempts: 12 + tables: + scenarios: 46 + scenario_fields: 47 + scenario_rules: 63 + sop_versions: 48 + sop_nodes: 49 + sop_edges: 50 + knowledge_items: 64 + knowledge_relations: 65 + knowledge_versions: 51 + runs: 52 + feedback: 53 diff --git a/configs/config.yml b/configs/config.yml index 7d7f481..5d8605f 100644 --- a/configs/config.yml +++ b/configs/config.yml @@ -25,22 +25,22 @@ seed: admin_password: admin123 admin_display_name: 平台管理员 multitable: - enabled: false + enabled: true base_url: https://table.iwork-ai.com/open/v1 - api_key: "" + api_key: iqd_6dd7293ce4d50f02949fe35bea669a0b156a4143f11ed5525aafe76e2c089685 sync_interval: 5s request_timeout: 10s batch_size: 20 max_attempts: 12 tables: - scenarios: 0 - scenario_fields: 0 - scenario_rules: 0 - sop_versions: 0 - sop_nodes: 0 - sop_edges: 0 - knowledge_items: 0 - knowledge_relations: 0 - knowledge_versions: 0 - runs: 0 - feedback: 0 + scenarios: 46 + scenario_fields: 47 + scenario_rules: 63 + sop_versions: 48 + sop_nodes: 49 + sop_edges: 50 + knowledge_items: 64 + knowledge_relations: 65 + knowledge_versions: 51 + runs: 52 + feedback: 53 diff --git a/internal/config/config.go b/internal/config/config.go index 50a8209..22f96f2 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -137,14 +137,6 @@ func Load(options LoadOptions) (Config, error) { if environment != "" { cfg.App.Env = environment } - if cfg.App.Env == "prod" { - if strings.TrimSpace(os.Getenv("APP_DATABASE_PASSWORD")) == "" { - return Config{}, errors.New("APP_DATABASE_PASSWORD must be set in production") - } - if strings.TrimSpace(os.Getenv("APP_AUTH_JWT_SECRET")) == "" { - return Config{}, errors.New("APP_AUTH_JWT_SECRET must be set in production") - } - } if err := cfg.Validate(); err != nil { return Config{}, err } @@ -187,7 +179,7 @@ func (c Config) Validate() error { return errors.New("multitable.base_url must use https when multitable is enabled") } if strings.TrimSpace(c.MultiTable.APIKey) == "" { - return errors.New("APP_MULTITABLE_API_KEY is required when multitable is enabled") + return errors.New("multitable.api_key is required when multitable is enabled") } if c.MultiTable.SyncInterval <= 0 || c.MultiTable.RequestTimeout <= 0 || c.MultiTable.BatchSize < 1 || c.MultiTable.MaxAttempts < 1 { return errors.New("multitable retry and timeout settings must be positive") diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 0ff0917..859bae9 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -3,7 +3,6 @@ package config import ( "os" "path/filepath" - "strings" "testing" ) @@ -69,24 +68,14 @@ database: } } -func TestLoadProductionRequiresEnvironmentSecrets(t *testing.T) { - dir := writeConfigs(t, "app:\n env: production\n") - t.Setenv("APP_DATABASE_PASSWORD", "") - t.Setenv("APP_AUTH_JWT_SECRET", "") - - _, err := Load(LoadOptions{Environment: "prod", ConfigDir: dir}) - if err == nil || !strings.Contains(err.Error(), "APP_DATABASE_PASSWORD") { - t.Fatalf("Load() error = %v, want production password requirement", err) - } - - t.Setenv("APP_DATABASE_PASSWORD", "production-password") - t.Setenv("APP_AUTH_JWT_SECRET", "production-jwt-secret") +func TestLoadProductionSecretsFromConfig(t *testing.T) { + dir := writeConfigs(t, "app:\n env: production\ndatabase:\n password: production-password\nauth:\n jwt_secret: production-jwt-secret\n") cfg, err := Load(LoadOptions{Environment: "prod", ConfigDir: dir}) if err != nil { - t.Fatalf("Load() with environment secrets error = %v", err) + t.Fatalf("Load() with config secrets error = %v", err) } if cfg.Database.Password != "production-password" || cfg.Auth.JWTSecret != "production-jwt-secret" { - t.Fatalf("environment secrets were not applied") + t.Fatalf("config secrets were not applied") } } diff --git a/internal/multitable/worker.go b/internal/multitable/worker.go index d0ba8f1..d07be96 100644 --- a/internal/multitable/worker.go +++ b/internal/multitable/worker.go @@ -2,6 +2,7 @@ package multitable import ( "context" + "errors" "fmt" "time" @@ -75,7 +76,9 @@ func (w *Worker) claim() []model.MultiTableOutbox { func (w *Worker) retry(event model.MultiTableOutbox, cause error) { status := "pending" availableAt := time.Now().Add(backoff(event.Attempts)) - if event.Attempts >= w.config.MaxAttempts { + // A missing source row cannot be repaired by retrying. This commonly occurs + // for audit events created before a source record was deleted. + if errors.Is(cause, gorm.ErrRecordNotFound) || event.Attempts >= w.config.MaxAttempts { status = "failed" } message := truncate(cause.Error(), 1024)