The GthulhuPlugin has been refactored to follow the singleton pattern, where all global variables and package-level functions have been embedded into the GthulhuPlugin struct. This allows developers to create independent instances of the plugin with isolated state.
Previously, the plugin used global variables that were shared across all code:
SLICE_NS_DEFAULTandSLICE_NS_MIN- scheduler configurationtaskPool,taskPoolCount,taskPoolHead,taskPoolTail- task pool stateminVruntime- global vruntime trackingstrategyMap- PID-based scheduling strategiesjwtClient- JWT client for API authentication
Package-level functions accessed these global variables directly.
Now, all state is encapsulated within the GthulhuPlugin struct:
type GthulhuPlugin struct {
// Scheduler configuration
sliceNsDefault uint64
sliceNsMin uint64
// Task pool state
taskPool []Task
taskPoolCount int
taskPoolHead int
taskPoolTail int
// Global vruntime
minVruntime uint64
// Strategy map for PID-based scheduling strategies
strategyMap map[int32]SchedulingStrategy
// JWT client for API authentication
jwtClient *JWTClient
// Metrics client for sending metrics to API server
metricsClient *MetricsClient
}// Create a new plugin instance with custom configuration
plugin := gthulhu.NewGthulhuPlugin(10000*1000, 1000*1000) // 10ms default, 1ms min
// Or use default configuration (5ms default, 0.5ms min)
plugin := gthulhu.NewGthulhuPlugin(0, 0)// Create two independent plugin instances
plugin1 := gthulhu.NewGthulhuPlugin(5000*1000, 500*1000)
plugin2 := gthulhu.NewGthulhuPlugin(10000*1000, 1000*1000)
// Each instance maintains its own state
// Changes to plugin1 do not affect plugin2plugin := gthulhu.NewGthulhuPlugin(0, 0)
// Initialize JWT client for API authentication
err := plugin.InitJWTClient("/path/to/public.key", "https://api.example.com")
if err != nil {
log.Fatal(err)
}
// Initialize metrics client (requires JWT client to be initialized first)
err = plugin.InitMetricsClient("https://api.example.com")
if err != nil {
log.Fatal(err)
}plugin := gthulhu.NewGthulhuPlugin(0, 0)
// Manually update strategy map
strategies := []gthulhu.SchedulingStrategy{
{PID: 100, Priority: true, ExecutionTime: 10000},
{PID: 200, Priority: false, ExecutionTime: 20000},
}
plugin.UpdateStrategyMap(strategies)
// Or start automatic strategy fetching (requires JWT client)
ctx := context.Background()
plugin.StartStrategyFetcher(ctx, "https://api.example.com/strategies", 30*time.Second)// Create plugin instance
plugin := gthulhu.NewGthulhuPlugin(0, 0)
// The plugin implements the plugin.CustomScheduler interface
// and can be loaded into the Gthulhu scheduler
scheduler.LoadPlugin(plugin)- Instance Isolation: Each plugin instance maintains its own state, allowing multiple independent schedulers
- No Global State: Eliminates global variable pollution and race conditions
- Testability: Easier to test since each test can create isolated instances
- Thread Safety: Each instance's state is independent, reducing contention
- Flexibility: Developers can create multiple plugin instances with different configurations
GetSchedulerConfig() (uint64, uint64)- Get current scheduler configurationSetSchedulerConfig(sliceNsDefault, sliceNsMin uint64)- Update scheduler configurationInitJWTClient(publicKeyPath, apiBaseURL string) error- Initialize JWT clientGetJWTClient() *JWTClient- Get JWT client instanceInitMetricsClient(apiBaseURL string) error- Initialize metrics clientGetMetricsClient() *MetricsClient- Get metrics client instanceFetchSchedulingStrategies(apiUrl string) ([]SchedulingStrategy, error)- Fetch strategiesUpdateStrategyMap(strategies []SchedulingStrategy)- Update strategy mapStartStrategyFetcher(ctx context.Context, apiUrl string, interval time.Duration)- Start periodic fetching
The following package-level functions have been removed:
SetSchedulerConfig()- Useplugin.SetSchedulerConfig()insteadGetSchedulerConfig()- Useplugin.GetSchedulerConfig()insteadInitJWTClient()- Useplugin.InitJWTClient()insteadGetJWTClient()- Useplugin.GetJWTClient()insteadFetchSchedulingStrategies()- Useplugin.FetchSchedulingStrategies()insteadUpdateStrategyMap()- Useplugin.UpdateStrategyMap()insteadStartStrategyFetcher()- Useplugin.StartStrategyFetcher()insteadGetTaskExecutionTime()- Internal method, not exposedApplySchedulingStrategy()- Internal method, not exposedGetPoolCount()- Useplugin.GetPoolCount()insteadGetTaskFromPool()- Internal method, not exposed
If you were previously using the global functions, migrate as follows:
// Before
InitJWTClient("/path/to/key", "https://api.example.com")
StartStrategyFetcher(ctx, apiUrl, interval)
// After
plugin := NewGthulhuPlugin(0, 0)
plugin.InitJWTClient("/path/to/key", "https://api.example.com")
plugin.StartStrategyFetcher(ctx, apiUrl, interval)The refactoring includes comprehensive tests in gthulhu_test.go:
- Instance isolation verification
- Default configuration testing
- Task pool initialization
- Strategy map management
- Configuration updates
Run tests with:
go test ./plugin/gthulhu/...