Rate limit fixes

This commit is contained in:
anonpenguin23 2026-02-06 11:09:34 +02:00
parent 7690b22c0a
commit b382350f76
7 changed files with 44 additions and 24 deletions

View File

@ -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 {

View File

@ -174,20 +174,27 @@ func GetProductionServices() []string {
}
}
// Also discover namespace-specific services (debros-*@<namespace>.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)
}
}
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -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)
}

View File

@ -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 &copy
}