mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-02 14:56:38 +08:00
merge: feat(core): implement cordis configuration extension and migrate all plugins
This commit is contained in:
@@ -7,7 +7,6 @@ package driver_asynq_cron
|
||||
import (
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
"Wavelet/pkg/config"
|
||||
"context"
|
||||
"embed"
|
||||
"encoding/json"
|
||||
@@ -84,10 +83,45 @@ func (p *Plugin) Name() string {
|
||||
return "driver_asynq_cron"
|
||||
}
|
||||
|
||||
type redisCronConfig struct {
|
||||
Enabled bool `config:"enabled" env:"REDIS_ENABLED" default:"false" autoEnable:"REDIS_ADDR"`
|
||||
Addrs []string `config:"addrs" env:"REDIS_ADDR"`
|
||||
Username string `config:"username" env:"REDIS_USERNAME"`
|
||||
Password string `config:"password" env:"REDIS_PASSWORD" secret:"true"`
|
||||
DB int `config:"db" env:"REDIS_DB"`
|
||||
}
|
||||
|
||||
// DeclareConfig declares configuration bindings for driver_asynq_cron.
|
||||
func (p *Plugin) DeclareConfig() []core.ConfigBinding {
|
||||
return []core.ConfigBinding{
|
||||
{Prefix: "redis", Target: &redisCronConfig{}},
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigEnabled gates plugin activation when Redis is enabled.
|
||||
func (p *Plugin) ConfigEnabled(view core.ConfigView) bool {
|
||||
return view.Bool("redis.enabled", false)
|
||||
}
|
||||
|
||||
// Apply mounts the Asynq Cron Scheduler driver into the micro-kernel Context.
|
||||
func (p *Plugin) Apply(ctx *core.Context) error {
|
||||
var rCfg redisCronConfig
|
||||
_ = ctx.Config().Bind("redis", &rCfg)
|
||||
|
||||
p.mu.Lock()
|
||||
p.coreCtx = ctx
|
||||
if p.redisOpt == nil {
|
||||
addr := "127.0.0.1:6379"
|
||||
if len(rCfg.Addrs) > 0 && rCfg.Addrs[0] != "" {
|
||||
addr = rCfg.Addrs[0]
|
||||
}
|
||||
p.redisOpt = asynq.RedisClientOpt{
|
||||
Addr: addr,
|
||||
Username: rCfg.Username,
|
||||
Password: rCfg.Password,
|
||||
DB: rCfg.DB,
|
||||
}
|
||||
}
|
||||
p.mu.Unlock()
|
||||
|
||||
// Bind DBService
|
||||
@@ -263,15 +297,7 @@ func (p *Plugin) resolveRedisOpt() asynq.RedisConnOpt {
|
||||
if RedisOpt != nil {
|
||||
return RedisOpt
|
||||
}
|
||||
redisCfg := config.Config.Redis
|
||||
addr := "127.0.0.1:6379"
|
||||
if len(redisCfg.Addrs) > 0 && redisCfg.Addrs[0] != "" {
|
||||
addr = redisCfg.Addrs[0]
|
||||
}
|
||||
return asynq.RedisClientOpt{
|
||||
Addr: addr,
|
||||
Username: redisCfg.Username,
|
||||
Password: redisCfg.Password,
|
||||
DB: redisCfg.DB,
|
||||
Addr: "127.0.0.1:6379",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package driver_asynq_worker
|
||||
|
||||
type queueConfig struct {
|
||||
Name string `config:"name"`
|
||||
Priority int `config:"priority"`
|
||||
}
|
||||
|
||||
type workerConfig struct {
|
||||
Concurrency int `config:"concurrency" env:"WORKER_CONCURRENCY" default:"10"`
|
||||
StrictPriority bool `config:"strict_priority" env:"WORKER_STRICT_PRIORITY" default:"false"`
|
||||
Queues []queueConfig `config:"queues"`
|
||||
}
|
||||
|
||||
type redisWorkerConfig struct {
|
||||
Enabled bool `config:"enabled" env:"REDIS_ENABLED" default:"false" autoEnable:"REDIS_ADDR"`
|
||||
Addrs []string `config:"addrs" env:"REDIS_ADDR"`
|
||||
Username string `config:"username" env:"REDIS_USERNAME"`
|
||||
Password string `config:"password" env:"REDIS_PASSWORD" secret:"true"`
|
||||
DB int `config:"db" env:"REDIS_DB"`
|
||||
ClusterMode bool `config:"cluster_mode" env:"REDIS_CLUSTER_MODE"`
|
||||
MasterName string `config:"master_name" env:"REDIS_MASTER_NAME"`
|
||||
KeyPrefix string `config:"key_prefix" env:"REDIS_KEY_PREFIX"`
|
||||
PoolSize int `config:"pool_size" env:"REDIS_POOL_SIZE"`
|
||||
MaintNotifications bool `config:"maint_notifications" env:"REDIS_MAINT_NOTIFICATIONS" default:"false"`
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
package driver_asynq_worker
|
||||
|
||||
import (
|
||||
"Wavelet/pkg/idgen"
|
||||
"Wavelet/pkg/testhelper"
|
||||
"context"
|
||||
"errors"
|
||||
@@ -22,6 +23,10 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
_ = idgen.Init(1)
|
||||
}
|
||||
|
||||
type mockDBService struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
@@ -108,10 +108,44 @@ func (p *Plugin) Name() string {
|
||||
return "driver_asynq_worker"
|
||||
}
|
||||
|
||||
// DeclareConfig declares configuration bindings consumed by the Asynq worker driver.
|
||||
func (p *Plugin) DeclareConfig() []core.ConfigBinding {
|
||||
return []core.ConfigBinding{
|
||||
{Prefix: "worker", Target: &workerConfig{}},
|
||||
{Prefix: "redis", Target: &redisWorkerConfig{}},
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigEnabled gates plugin activation when Redis is enabled.
|
||||
func (p *Plugin) ConfigEnabled(view core.ConfigView) bool {
|
||||
return view.Bool("redis.enabled", false)
|
||||
}
|
||||
|
||||
// Apply mounts the Asynq Worker driver into the micro-kernel Context.
|
||||
func (p *Plugin) Apply(ctx *core.Context) error {
|
||||
var wCfg workerConfig
|
||||
_ = ctx.Config().Bind("worker", &wCfg)
|
||||
var rCfg redisWorkerConfig
|
||||
_ = ctx.Config().Bind("redis", &rCfg)
|
||||
|
||||
p.mu.Lock()
|
||||
p.coreCtx = ctx
|
||||
if p.concurrency == defaultConcurrency && wCfg.Concurrency > 0 {
|
||||
p.concurrency = wCfg.Concurrency
|
||||
}
|
||||
p.strictPriority = wCfg.StrictPriority
|
||||
if len(p.queues) == 1 && p.queues["default"] == 1 && len(wCfg.Queues) > 0 {
|
||||
qMap := make(map[string]int, len(wCfg.Queues))
|
||||
for _, q := range wCfg.Queues {
|
||||
qMap[q.Name] = q.Priority
|
||||
}
|
||||
p.queues = qMap
|
||||
}
|
||||
if p.redisOpt == nil {
|
||||
p.redisOpt = NewRedisConnOptWithConfig(rCfg)
|
||||
}
|
||||
RedisOpt = p.redisOpt
|
||||
ResetAsynqClient()
|
||||
p.mu.Unlock()
|
||||
|
||||
// 0. Bind DBService
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package driver_asynq_worker
|
||||
|
||||
import (
|
||||
"Wavelet/pkg/config"
|
||||
"sync"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
@@ -72,8 +71,11 @@ func GetAsynqClient() *asynq.Client {
|
||||
return AsynqClient
|
||||
}
|
||||
|
||||
opt := NewRedisConnOpt()
|
||||
RedisOpt = opt
|
||||
opt := RedisOpt
|
||||
if opt == nil {
|
||||
opt = NewRedisConnOpt()
|
||||
RedisOpt = opt
|
||||
}
|
||||
AsynqClient = asynq.NewClient(opt)
|
||||
return AsynqClient
|
||||
}
|
||||
@@ -88,9 +90,33 @@ func ResetAsynqClient() {
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
keyPrefixMu sync.RWMutex
|
||||
keyPrefix string
|
||||
)
|
||||
|
||||
// SetKeyPrefix sets the redis key prefix for queue names.
|
||||
func SetKeyPrefix(prefix string) {
|
||||
keyPrefixMu.Lock()
|
||||
defer keyPrefixMu.Unlock()
|
||||
keyPrefix = prefix
|
||||
}
|
||||
|
||||
// GetKeyPrefix returns the redis key prefix for queue names.
|
||||
func GetKeyPrefix() string {
|
||||
keyPrefixMu.RLock()
|
||||
defer keyPrefixMu.RUnlock()
|
||||
return keyPrefix
|
||||
}
|
||||
|
||||
// NewRedisConnOpt 根据配置返回对应的 asynq Redis 连接选项
|
||||
func NewRedisConnOpt() asynq.RedisConnOpt {
|
||||
cfg := config.Config.Redis
|
||||
return NewRedisConnOptWithConfig(redisWorkerConfig{})
|
||||
}
|
||||
|
||||
// NewRedisConnOptWithConfig returns the asynq RedisConnOpt based on the provided configuration.
|
||||
func NewRedisConnOptWithConfig(cfg redisWorkerConfig) asynq.RedisConnOpt {
|
||||
SetKeyPrefix(cfg.KeyPrefix)
|
||||
addrs := cfg.Addrs
|
||||
|
||||
if cfg.ClusterMode {
|
||||
@@ -135,7 +161,7 @@ func NewRedisConnOpt() asynq.RedisConnOpt {
|
||||
|
||||
// PrefixedQueue 返回带前缀的队列名,用于 Cluster 模式隔离
|
||||
func PrefixedQueue(queue string) string {
|
||||
prefix := config.Config.Redis.KeyPrefix
|
||||
prefix := GetKeyPrefix()
|
||||
if prefix == "" {
|
||||
return queue
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package driver_asynq_worker
|
||||
|
||||
import (
|
||||
"Wavelet/pkg/config"
|
||||
"testing"
|
||||
|
||||
"github.com/redis/go-redis/v9/maintnotifications"
|
||||
@@ -42,17 +41,17 @@ func TestMaintNotificationsConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPrefixedQueue(t *testing.T) {
|
||||
oldPrefix := config.Config.Redis.KeyPrefix
|
||||
oldPrefix := GetKeyPrefix()
|
||||
defer func() {
|
||||
config.Config.Redis.KeyPrefix = oldPrefix
|
||||
SetKeyPrefix(oldPrefix)
|
||||
}()
|
||||
|
||||
config.Config.Redis.KeyPrefix = "test:"
|
||||
SetKeyPrefix("test:")
|
||||
if got := PrefixedQueue("default"); got != "test:default" {
|
||||
t.Fatalf("PrefixedQueue() = %q, want %q", got, "test:default")
|
||||
}
|
||||
|
||||
config.Config.Redis.KeyPrefix = ""
|
||||
SetKeyPrefix("")
|
||||
if got := PrefixedQueue("default"); got != "default" {
|
||||
t.Fatalf("PrefixedQueue() = %q, want %q", got, "default")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package driver_http
|
||||
|
||||
type httpAppConfig struct {
|
||||
Addr string `config:"addr" env:"APP_ADDR" default:":8000"`
|
||||
AppName string `config:"app_name" env:"APP_NAME" default:"Wavelet"`
|
||||
APIPrefix string `config:"api_prefix" env:"APP_API_PREFIX" default:"/api/v1"`
|
||||
Env string `config:"env" env:"APP_ENV" default:"development"`
|
||||
GracefulShutdownTimeout int `config:"graceful_shutdown_timeout" env:"APP_GRACEFUL_SHUTDOWN_TIMEOUT" default:"30"`
|
||||
SessionCookieName string `config:"session_cookie_name" env:"APP_SESSION_COOKIE_NAME" default:"wavelet_session"`
|
||||
SessionSecret string `config:"session_secret" env:"APP_SESSION_SECRET" secret:"true"`
|
||||
SessionDomain string `config:"session_domain" env:"APP_SESSION_DOMAIN"`
|
||||
SessionAge int `config:"session_age" env:"APP_SESSION_AGE" default:"86400"`
|
||||
SessionHTTPOnly bool `config:"session_http_only" env:"APP_SESSION_HTTP_ONLY" default:"true"`
|
||||
SessionSecure bool `config:"session_secure" env:"APP_SESSION_SECURE"`
|
||||
}
|
||||
|
||||
type httpRedisConfig struct {
|
||||
Addrs []string `config:"addrs" env:"REDIS_ADDR"`
|
||||
Username string `config:"username" env:"REDIS_USERNAME"`
|
||||
Password string `config:"password" env:"REDIS_PASSWORD" secret:"true"`
|
||||
DB int `config:"db" env:"REDIS_DB"`
|
||||
KeyPrefix string `config:"key_prefix" env:"REDIS_KEY_PREFIX"`
|
||||
MinIdleConn int `config:"min_idle_conn" env:"REDIS_MIN_IDLE_CONN"`
|
||||
}
|
||||
@@ -4,19 +4,9 @@
|
||||
package driver_http
|
||||
|
||||
import (
|
||||
"Wavelet/pkg/config"
|
||||
"Wavelet/pkg/trace"
|
||||
"Wavelet/pkg/util"
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-contrib/sessions/redis"
|
||||
@@ -26,102 +16,82 @@ import (
|
||||
|
||||
// BuildEngine 构建并初始化 Gin 路由引擎及全部中间件和路由
|
||||
func BuildEngine() (*gin.Engine, error) {
|
||||
return BuildEngineWithConfig(httpAppConfig{}, httpRedisConfig{})
|
||||
}
|
||||
|
||||
// BuildEngineWithConfig constructs the Gin engine with explicitly injected configuration.
|
||||
func BuildEngineWithConfig(appCfg httpAppConfig, redisCfg httpRedisConfig) (*gin.Engine, error) {
|
||||
// 运行模式
|
||||
if config.Config.App.IsProduction() {
|
||||
if appCfg.Env == "production" || appCfg.Env == "prod" {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
setAPIPrefix(appCfg.APIPrefix)
|
||||
|
||||
// 初始化路由
|
||||
r := gin.New()
|
||||
r.Use(gin.Recovery())
|
||||
r.Use(corsMiddleware())
|
||||
|
||||
cfg := config.Config.Redis
|
||||
addrs := cfg.Addrs
|
||||
addrs := redisCfg.Addrs
|
||||
sessionAddr := "localhost:6379"
|
||||
if len(addrs) > 0 {
|
||||
sessionAddr = addrs[0]
|
||||
}
|
||||
|
||||
sessionSecret := appCfg.SessionSecret
|
||||
if sessionSecret == "" {
|
||||
sessionSecret = "wavelet-default-session-secret"
|
||||
}
|
||||
|
||||
sessionStore, err := redis.NewStoreWithDB(
|
||||
cfg.MinIdleConn,
|
||||
redisCfg.MinIdleConn,
|
||||
"tcp",
|
||||
sessionAddr,
|
||||
cfg.Username,
|
||||
cfg.Password,
|
||||
strconv.Itoa(cfg.DB),
|
||||
[]byte(config.Config.App.SessionSecret),
|
||||
redisCfg.Username,
|
||||
redisCfg.Password,
|
||||
strconv.Itoa(redisCfg.DB),
|
||||
[]byte(sessionSecret),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 设置 Session Redis Key 前缀
|
||||
if cfg.KeyPrefix != "" {
|
||||
if err := redis.SetKeyPrefix(sessionStore, cfg.KeyPrefix+"session:"); err != nil {
|
||||
if redisCfg.KeyPrefix != "" {
|
||||
if err := redis.SetKeyPrefix(sessionStore, redisCfg.KeyPrefix+"session:"); err != nil {
|
||||
log.Printf("[API] set session key prefix failed: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
sessionCookieName := appCfg.SessionCookieName
|
||||
if sessionCookieName == "" {
|
||||
sessionCookieName = "wavelet_session"
|
||||
}
|
||||
|
||||
sessionAge := appCfg.SessionAge
|
||||
if sessionAge <= 0 {
|
||||
sessionAge = 86400
|
||||
}
|
||||
|
||||
sessionStore.Options(sessions.Options{
|
||||
Path: "/",
|
||||
Domain: config.Config.App.SessionDomain,
|
||||
MaxAge: config.Config.App.SessionAge,
|
||||
HttpOnly: config.Config.App.SessionHTTPOnly,
|
||||
Secure: config.Config.App.SessionSecure,
|
||||
Domain: appCfg.SessionDomain,
|
||||
MaxAge: sessionAge,
|
||||
HttpOnly: appCfg.SessionHTTPOnly,
|
||||
Secure: appCfg.SessionSecure,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
})
|
||||
|
||||
r.Use(sessions.Sessions(config.Config.App.SessionCookieName, sessionStore))
|
||||
r.Use(sessions.Sessions(sessionCookieName, sessionStore))
|
||||
|
||||
appName := appCfg.AppName
|
||||
if appName == "" {
|
||||
appName = "Wavelet"
|
||||
}
|
||||
|
||||
// 补充中间件
|
||||
r.Use(otelgin.Middleware(config.Config.App.AppName), errorHandlerMiddleware(), loggerMiddleware())
|
||||
r.Use(otelgin.Middleware(appName), errorHandlerMiddleware(), loggerMiddleware())
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Serve 启动 HTTP API 服务。onStarted 仅会在 HTTP 地址成功绑定后调用。
|
||||
func Serve(onStarted func()) {
|
||||
r, err := BuildEngine()
|
||||
if err != nil {
|
||||
log.Fatalf("[API] init session store failed: %v\n", err)
|
||||
}
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: config.Config.App.Addr,
|
||||
Handler: r,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
listener, err := (&net.ListenConfig{}).Listen(context.Background(), "tcp", config.Config.App.Addr)
|
||||
if err != nil {
|
||||
log.Fatalf("[API] server failed to listen on %s: %v\n", config.Config.App.Addr, err)
|
||||
}
|
||||
if onStarted != nil {
|
||||
onStarted()
|
||||
}
|
||||
|
||||
util.Go(func() {
|
||||
log.Printf("[API] server listening on %s\n", config.Config.App.Addr)
|
||||
if err := srv.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
log.Fatalf("[API] server failed: %v\n", err)
|
||||
}
|
||||
})
|
||||
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
|
||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), time.Duration(config.Config.App.GracefulShutdownTimeout)*time.Second)
|
||||
|
||||
trace.Shutdown(shutdownCtx)
|
||||
|
||||
if err := srv.Shutdown(shutdownCtx); err != nil {
|
||||
log.Printf("[API] server forced to shutdown: %v\n", err)
|
||||
cancel()
|
||||
os.Exit(1)
|
||||
}
|
||||
cancel()
|
||||
|
||||
log.Println("[API] server exited")
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
package driver_http
|
||||
|
||||
import (
|
||||
"Wavelet/pkg/config"
|
||||
"Wavelet/pkg/logger"
|
||||
"Wavelet/pkg/response"
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -21,6 +21,26 @@ import (
|
||||
otel_trace "Wavelet/pkg/trace"
|
||||
)
|
||||
|
||||
var (
|
||||
apiPrefixMu sync.RWMutex
|
||||
apiPrefix = "/api/v1"
|
||||
)
|
||||
|
||||
func setAPIPrefix(prefix string) {
|
||||
if prefix == "" {
|
||||
return
|
||||
}
|
||||
apiPrefixMu.Lock()
|
||||
defer apiPrefixMu.Unlock()
|
||||
apiPrefix = prefix
|
||||
}
|
||||
|
||||
func getAPIPrefix() string {
|
||||
apiPrefixMu.RLock()
|
||||
defer apiPrefixMu.RUnlock()
|
||||
return apiPrefix
|
||||
}
|
||||
|
||||
func loggerMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 初始化 Trace
|
||||
@@ -46,7 +66,7 @@ func loggerMiddleware() gin.HandlerFunc {
|
||||
|
||||
// 打印日志
|
||||
// 排除健康检查接口
|
||||
healthPath := config.Config.App.APIPrefix + "/health"
|
||||
healthPath := getAPIPrefix() + "/health"
|
||||
if c.Request.URL.Path != healthPath {
|
||||
logger.InfoF(
|
||||
ctx,
|
||||
|
||||
@@ -91,10 +91,31 @@ func (p *Plugin) Name() string {
|
||||
return "driver_http"
|
||||
}
|
||||
|
||||
// DeclareConfig declares configuration bindings for driver_http.
|
||||
func (p *Plugin) DeclareConfig() []core.ConfigBinding {
|
||||
return []core.ConfigBinding{
|
||||
{Prefix: "app", Target: &httpAppConfig{}},
|
||||
{Prefix: "redis", Target: &httpRedisConfig{}},
|
||||
}
|
||||
}
|
||||
|
||||
// Apply mounts the HTTP driver plugin into the micro-kernel Context.
|
||||
func (p *Plugin) Apply(ctx *core.Context) error {
|
||||
var appCfg httpAppConfig
|
||||
if err := ctx.Config().Bind("app", &appCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
var redisCfg httpRedisConfig
|
||||
_ = ctx.Config().Bind("redis", &redisCfg)
|
||||
|
||||
p.mu.Lock()
|
||||
p.coreCtx = ctx
|
||||
if p.addr == defaultAddr && appCfg.Addr != "" {
|
||||
p.addr = appCfg.Addr
|
||||
}
|
||||
if appCfg.GracefulShutdownTimeout > 0 {
|
||||
p.shutdownTimeout = time.Duration(appCfg.GracefulShutdownTimeout) * time.Second
|
||||
}
|
||||
p.mu.Unlock()
|
||||
|
||||
// Bind DBService from Context
|
||||
@@ -147,7 +168,17 @@ func (p *Plugin) Start(ctx context.Context) error {
|
||||
}
|
||||
|
||||
if p.engine == nil {
|
||||
p.engine = gin.New()
|
||||
var appCfg httpAppConfig
|
||||
var redisCfg httpRedisConfig
|
||||
if p.coreCtx != nil {
|
||||
_ = p.coreCtx.Config().Bind("app", &appCfg)
|
||||
_ = p.coreCtx.Config().Bind("redis", &redisCfg)
|
||||
}
|
||||
var err error
|
||||
p.engine, err = BuildEngineWithConfig(appCfg, redisCfg)
|
||||
if err != nil {
|
||||
p.engine = gin.New()
|
||||
}
|
||||
}
|
||||
|
||||
// Mount routes collected in Context RouterExtension
|
||||
|
||||
@@ -38,6 +38,22 @@ func (p *Plugin) Manifest() core.Manifest {
|
||||
}
|
||||
}
|
||||
|
||||
type redisGateConfig struct {
|
||||
Enabled bool `config:"enabled" env:"REDIS_ENABLED" default:"false" autoEnable:"REDIS_ADDR"`
|
||||
}
|
||||
|
||||
// DeclareConfig declares configuration bindings for driver_inproc_cron.
|
||||
func (p *Plugin) DeclareConfig() []core.ConfigBinding {
|
||||
return []core.ConfigBinding{
|
||||
{Prefix: "redis", Target: &redisGateConfig{}},
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigEnabled gates plugin activation when Redis is disabled.
|
||||
func (p *Plugin) ConfigEnabled(view core.ConfigView) bool {
|
||||
return !view.Bool("redis.enabled", false)
|
||||
}
|
||||
|
||||
// Apply registers the scheduler driver into the Context.
|
||||
func (p *Plugin) Apply(ctx *core.Context) error {
|
||||
p.mu.Lock()
|
||||
|
||||
@@ -98,6 +98,22 @@ func (p *Plugin) Manifest() core.Manifest {
|
||||
}
|
||||
}
|
||||
|
||||
type redisGateConfig struct {
|
||||
Enabled bool `config:"enabled" env:"REDIS_ENABLED" default:"false" autoEnable:"REDIS_ADDR"`
|
||||
}
|
||||
|
||||
// DeclareConfig declares the configuration bindings consumed by this plugin.
|
||||
func (p *Plugin) DeclareConfig() []core.ConfigBinding {
|
||||
return []core.ConfigBinding{
|
||||
{Prefix: "redis", Target: &redisGateConfig{}},
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigEnabled gates plugin activation when Redis is disabled.
|
||||
func (p *Plugin) ConfigEnabled(view core.ConfigView) bool {
|
||||
return !view.Bool("redis.enabled", false)
|
||||
}
|
||||
|
||||
// Apply registers the worker driver and provides contracts.TaskService.
|
||||
func (p *Plugin) Apply(ctx *core.Context) error {
|
||||
p.coreCtx = ctx
|
||||
|
||||
@@ -6,6 +6,7 @@ package driver_inproc_worker_test
|
||||
import (
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/extpoints"
|
||||
"Wavelet/pkg/idgen"
|
||||
"Wavelet/plugins/drivers/driver_inproc_worker"
|
||||
"context"
|
||||
"sync/atomic"
|
||||
@@ -17,6 +18,7 @@ import (
|
||||
)
|
||||
|
||||
func TestInprocWorkerPlugin(t *testing.T) {
|
||||
require.NoError(t, idgen.Init(1))
|
||||
ctx := core.NewContext(context.Background())
|
||||
p := driver_inproc_worker.New(
|
||||
driver_inproc_worker.WithConcurrency(2),
|
||||
|
||||
@@ -32,6 +32,8 @@ func init() {
|
||||
|
||||
func TestHTTPDriverLifecycle(t *testing.T) {
|
||||
ctx := core.NewContext(context.Background())
|
||||
ctx.Config().SetSource(core.NewMapSource(nil))
|
||||
require.NoError(t, ctx.Config().Resolve())
|
||||
|
||||
var globalMiddlewareCalled atomic.Bool
|
||||
var groupMiddlewareCalled atomic.Bool
|
||||
@@ -264,6 +266,8 @@ func TestMultipleDriversInContext(t *testing.T) {
|
||||
defer mr.Close()
|
||||
|
||||
ctx := core.NewContext(context.Background())
|
||||
ctx.Config().SetSource(core.NewMapSource(nil))
|
||||
require.NoError(t, ctx.Config().Resolve())
|
||||
|
||||
httpPlugin := driver_http.New(driver_http.WithAddr("127.0.0.1:0"))
|
||||
workerPlugin := driver_asynq_worker.New(driver_asynq_worker.WithRedisOpt(asynq.RedisClientOpt{Addr: mr.Addr()}))
|
||||
|
||||
Reference in New Issue
Block a user