diff --git a/pkg/cli/production/upgrade/orchestrator.go b/pkg/cli/production/upgrade/orchestrator.go index 6d017f9..9b46a35 100644 --- a/pkg/cli/production/upgrade/orchestrator.go +++ b/pkg/cli/production/upgrade/orchestrator.go @@ -618,6 +618,18 @@ func (o *Orchestrator) restartServices() error { // Get services to restart services := utils.GetProductionServices() + // Re-enable namespace services BEFORE restarting debros-node. + // orama prod stop disables them, and debros-node's PartOf= dependency + // won't propagate restart to disabled services. We must re-enable first + // so that namespace gateways restart with the updated binary. + for _, svc := range services { + if strings.Contains(svc, "@") { + if err := exec.Command("systemctl", "enable", svc).Run(); err != nil { + fmt.Printf(" ⚠️ Warning: Failed to re-enable %s: %v\n", svc, err) + } + } + } + // If this is a nameserver, also restart CoreDNS and Caddy if o.setup.IsNameserver() { nameserverServices := []string{"coredns", "caddy"} @@ -672,7 +684,7 @@ func (o *Orchestrator) restartServices() error { } } - // Start any remaining services not in priority list + // Start any remaining services not in priority list (includes namespace services) for _, svc := range services { found := false for _, priority := range priorityOrder { diff --git a/pkg/cli/utils/systemd.go b/pkg/cli/utils/systemd.go index 6d59962..c807bf9 100644 --- a/pkg/cli/utils/systemd.go +++ b/pkg/cli/utils/systemd.go @@ -174,20 +174,27 @@ func GetProductionServices() []string { } } - // Also discover namespace-specific services (debros-*@.service) - // These are created when namespaces are provisioned and need to be restarted too - systemdDir := "/etc/systemd/system" - entries, err := os.ReadDir(systemdDir) + // Discover namespace service instances from the namespaces data directory. + // We can't rely on scanning /etc/systemd/system because that only contains + // template files (e.g. debros-namespace-gateway@.service) with no instance name. + // Restarting a template without an instance is a no-op. + // Instead, scan the data directory where each subdirectory is a provisioned namespace. + namespacesDir := "/home/debros/.orama/data/namespaces" + nsEntries, err := os.ReadDir(namespacesDir) if err == nil { - for _, entry := range entries { - name := entry.Name() - // Look for debros-*@*.service pattern (namespace services) - if strings.HasPrefix(name, "debros-") && - strings.Contains(name, "@") && - strings.HasSuffix(name, ".service") { - // Extract service name without .service extension - serviceName := strings.TrimSuffix(name, ".service") - existing = append(existing, serviceName) + serviceTypes := []string{"rqlite", "olric", "gateway"} + for _, nsEntry := range nsEntries { + if !nsEntry.IsDir() { + continue + } + ns := nsEntry.Name() + for _, svcType := range serviceTypes { + // Only add if the env file exists (service was provisioned) + envFile := filepath.Join(namespacesDir, ns, svcType+".env") + if _, err := os.Stat(envFile); err == nil { + svcName := fmt.Sprintf("debros-namespace-%s@%s", svcType, ns) + existing = append(existing, svcName) + } } } } diff --git a/pkg/client/database_client.go b/pkg/client/database_client.go index e1104e7..cd8a85c 100644 --- a/pkg/client/database_client.go +++ b/pkg/client/database_client.go @@ -224,12 +224,14 @@ func (d *DatabaseClientImpl) connectToAvailableNode() (*gorqlite.Connection, err var conn *gorqlite.Connection var err error - // Disable gorqlite cluster discovery to avoid /nodes timeouts from unreachable peers + // Disable gorqlite cluster discovery to avoid /nodes timeouts from unreachable peers. + // Use level=none to read from local SQLite directly (no leader forwarding). + // Writes are unaffected — they always go through Raft consensus. openURL := rqliteURL if strings.Contains(openURL, "?") { - openURL += "&disableClusterDiscovery=true" + openURL += "&disableClusterDiscovery=true&level=none" } else { - openURL += "?disableClusterDiscovery=true" + openURL += "?disableClusterDiscovery=true&level=none" } conn, err = gorqlite.Open(openURL) if err != nil { diff --git a/pkg/gateway/dependencies.go b/pkg/gateway/dependencies.go index c583ad9..ba35f96 100644 --- a/pkg/gateway/dependencies.go +++ b/pkg/gateway/dependencies.go @@ -128,9 +128,9 @@ func initializeRQLite(logger *logging.ColoredLogger, cfg *Config, deps *Dependen } if strings.Contains(dsn, "?") { - dsn += "&disableClusterDiscovery=true" + dsn += "&disableClusterDiscovery=true&level=none" } else { - dsn += "?disableClusterDiscovery=true" + dsn += "?disableClusterDiscovery=true&level=none" } db, err := sql.Open("rqlite", dsn) if err != nil { diff --git a/pkg/gateway/gateway.go b/pkg/gateway/gateway.go index 2b78e40..8b59c4d 100644 --- a/pkg/gateway/gateway.go +++ b/pkg/gateway/gateway.go @@ -310,8 +310,8 @@ func New(logger *logging.ColoredLogger, cfg *Config) (*Gateway, error) { // Initialize request log batcher (flush every 5 seconds) gw.logBatcher = newRequestLogBatcher(gw, 5*time.Second, 100) - // Initialize rate limiter (300 req/min, burst 50) - gw.rateLimiter = NewRateLimiter(300, 50) + // Initialize rate limiter (10000 req/min, burst 5000) + gw.rateLimiter = NewRateLimiter(10000, 5000) gw.rateLimiter.StartCleanup(5*time.Minute, 10*time.Minute) // Initialize WireGuard peer exchange handler diff --git a/pkg/rqlite/adapter.go b/pkg/rqlite/adapter.go index 8b1b1cf..3a23ba8 100644 --- a/pkg/rqlite/adapter.go +++ b/pkg/rqlite/adapter.go @@ -17,7 +17,7 @@ type RQLiteAdapter struct { // NewRQLiteAdapter creates a new adapter that provides sql.DB interface for RQLite func NewRQLiteAdapter(manager *RQLiteManager) (*RQLiteAdapter, error) { // Use the gorqlite database/sql driver - db, err := sql.Open("rqlite", fmt.Sprintf("http://localhost:%d?disableClusterDiscovery=true", manager.config.RQLitePort)) + db, err := sql.Open("rqlite", fmt.Sprintf("http://localhost:%d?disableClusterDiscovery=true&level=none", manager.config.RQLitePort)) if err != nil { return nil, fmt.Errorf("failed to open RQLite SQL connection: %w", err) } diff --git a/pkg/serverless/config.go b/pkg/serverless/config.go index dd8216f..2ac8f54 100644 --- a/pkg/serverless/config.go +++ b/pkg/serverless/config.go @@ -62,7 +62,7 @@ func DefaultConfig() *Config { DefaultRetryDelaySeconds: 5, // Rate limiting - GlobalRateLimitPerMinute: 10000, // 10k requests/minute globally + GlobalRateLimitPerMinute: 250000, // 250k requests/minute globally // Background jobs JobWorkers: 4, @@ -184,4 +184,3 @@ func (c *Config) WithRateLimit(perMinute int) *Config { copy.GlobalRateLimitPerMinute = perMinute return © } -