feat: 🎉 postgresql broker first commit of forked prototype from my original code
This commit is contained in:
233
cmd/broker/main.go
Normal file
233
cmd/broker/main.go
Normal file
@@ -0,0 +1,233 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"git.warky.dev/wdevs/pgsql-broker/pkg/broker"
|
||||
"git.warky.dev/wdevs/pgsql-broker/pkg/broker/adapter"
|
||||
"git.warky.dev/wdevs/pgsql-broker/pkg/broker/config"
|
||||
"git.warky.dev/wdevs/pgsql-broker/pkg/broker/install"
|
||||
)
|
||||
|
||||
var (
|
||||
// Version information (injected by build)
|
||||
Version = "dev"
|
||||
BuildTime = "unknown"
|
||||
Commit = "unknown"
|
||||
|
||||
// Command line flags
|
||||
cfgFile string
|
||||
logLevel string
|
||||
verifyOnly bool
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "pgsql-broker",
|
||||
Short: "PostgreSQL job broker for background job processing",
|
||||
Long: `PostgreSQL Broker is a job processing system that uses PostgreSQL
|
||||
LISTEN/NOTIFY for event-driven job execution. It supports multiple queues,
|
||||
priority-based scheduling, and horizontal scaling.`,
|
||||
Version: fmt.Sprintf("%s (built %s, commit %s)", Version, BuildTime, Commit),
|
||||
}
|
||||
|
||||
var startCmd = &cobra.Command{
|
||||
Use: "start",
|
||||
Short: "Start the broker instance",
|
||||
Long: `Start the broker instance and begin processing jobs from the database queue.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runBroker()
|
||||
},
|
||||
}
|
||||
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print version information",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf("pgsql-broker version %s\n", Version)
|
||||
fmt.Printf("Built: %s\n", BuildTime)
|
||||
fmt.Printf("Commit: %s\n", Commit)
|
||||
},
|
||||
}
|
||||
|
||||
var installCmd = &cobra.Command{
|
||||
Use: "install",
|
||||
Short: "Install database schema (tables and procedures)",
|
||||
Long: `Install the required database schema including tables and stored procedures.
|
||||
This command will create all necessary tables and functions in the configured database.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runInstall()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(startCmd)
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
rootCmd.AddCommand(installCmd)
|
||||
|
||||
// Persistent flags
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is broker.yaml)")
|
||||
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "log level (debug, info, warn, error)")
|
||||
|
||||
// Install command flags
|
||||
installCmd.Flags().BoolVar(&verifyOnly, "verify-only", false, "only verify installation without installing")
|
||||
}
|
||||
|
||||
func runBroker() error {
|
||||
// Load configuration
|
||||
cfg, err := config.LoadConfig(cfgFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load config: %w", err)
|
||||
}
|
||||
|
||||
// Override log level if specified
|
||||
if logLevel != "" {
|
||||
cfg.Logging.Level = logLevel
|
||||
}
|
||||
|
||||
// Setup logger
|
||||
logger := createLogger(cfg.Logging)
|
||||
logger.Info("starting pgsql-broker", "version", Version, "databases", len(cfg.Databases))
|
||||
|
||||
// Create broker (manages all database instances)
|
||||
b, err := broker.New(cfg, logger, Version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create broker: %w", err)
|
||||
}
|
||||
|
||||
// Start the broker (starts all database instances)
|
||||
if err := b.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start broker: %w", err)
|
||||
}
|
||||
|
||||
// Wait for shutdown signal
|
||||
waitForShutdown(b, logger)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runInstall() error {
|
||||
// Load configuration
|
||||
cfg, err := config.LoadConfig(cfgFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load config: %w", err)
|
||||
}
|
||||
|
||||
// Override log level if specified
|
||||
if logLevel != "" {
|
||||
cfg.Logging.Level = logLevel
|
||||
}
|
||||
|
||||
// Setup logger
|
||||
logger := createLogger(cfg.Logging)
|
||||
logger.Info("pgsql-broker database installer", "version", Version, "databases", len(cfg.Databases))
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Install/verify on all configured databases
|
||||
for i, dbCfg := range cfg.Databases {
|
||||
logger.Info("processing database", "index", i, "name", dbCfg.Name, "host", dbCfg.Host, "database", dbCfg.Database)
|
||||
|
||||
// Create database adapter
|
||||
dbAdapter := adapter.NewPostgresAdapter(dbCfg.ToPostgresConfig(), logger)
|
||||
|
||||
// Connect to database
|
||||
if err := dbAdapter.Connect(ctx); err != nil {
|
||||
return fmt.Errorf("failed to connect to database %s: %w", dbCfg.Name, err)
|
||||
}
|
||||
|
||||
// Create installer
|
||||
installer := install.New(dbAdapter, logger)
|
||||
|
||||
if verifyOnly {
|
||||
// Only verify installation
|
||||
logger.Info("verifying database schema", "database", dbCfg.Name)
|
||||
if err := installer.VerifyInstallation(ctx); err != nil {
|
||||
dbAdapter.Close()
|
||||
logger.Error("verification failed", "database", dbCfg.Name, "error", err)
|
||||
return fmt.Errorf("verification failed for %s: %w", dbCfg.Name, err)
|
||||
}
|
||||
logger.Info("database schema verified successfully", "database", dbCfg.Name)
|
||||
} else {
|
||||
// Install schema
|
||||
logger.Info("installing database schema", "database", dbCfg.Name)
|
||||
if err := installer.InstallSchema(ctx); err != nil {
|
||||
dbAdapter.Close()
|
||||
logger.Error("installation failed", "database", dbCfg.Name, "error", err)
|
||||
return fmt.Errorf("installation failed for %s: %w", dbCfg.Name, err)
|
||||
}
|
||||
|
||||
// Verify installation
|
||||
logger.Info("verifying installation", "database", dbCfg.Name)
|
||||
if err := installer.VerifyInstallation(ctx); err != nil {
|
||||
dbAdapter.Close()
|
||||
logger.Error("verification failed", "database", dbCfg.Name, "error", err)
|
||||
return fmt.Errorf("verification failed for %s: %w", dbCfg.Name, err)
|
||||
}
|
||||
|
||||
logger.Info("database schema installed and verified successfully", "database", dbCfg.Name)
|
||||
}
|
||||
|
||||
dbAdapter.Close()
|
||||
}
|
||||
|
||||
if verifyOnly {
|
||||
logger.Info("all databases verified successfully")
|
||||
} else {
|
||||
logger.Info("all databases installed and verified successfully")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createLogger(cfg config.LoggingConfig) adapter.Logger {
|
||||
// Parse log level
|
||||
var level slog.Level
|
||||
switch cfg.Level {
|
||||
case "debug":
|
||||
level = slog.LevelDebug
|
||||
case "info":
|
||||
level = slog.LevelInfo
|
||||
case "warn":
|
||||
level = slog.LevelWarn
|
||||
case "error":
|
||||
level = slog.LevelError
|
||||
default:
|
||||
level = slog.LevelInfo
|
||||
}
|
||||
|
||||
// Create handler based on format
|
||||
var handler slog.Handler
|
||||
opts := &slog.HandlerOptions{Level: level}
|
||||
|
||||
if cfg.Format == "text" {
|
||||
handler = slog.NewTextHandler(os.Stdout, opts)
|
||||
} else {
|
||||
handler = slog.NewJSONHandler(os.Stdout, opts)
|
||||
}
|
||||
|
||||
return adapter.NewSlogLoggerWithHandler(handler)
|
||||
}
|
||||
|
||||
func waitForShutdown(b *broker.Broker, logger adapter.Logger) {
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
|
||||
|
||||
sig := <-sigChan
|
||||
logger.Info("received shutdown signal", "signal", sig)
|
||||
|
||||
if err := b.Stop(); err != nil {
|
||||
logger.Error("error during shutdown", "error", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user