Skip to content

feat: add OFFLINE_GRACE_PERIOD env to extend keepAlive timeout#33

Closed
kilyabin wants to merge 1 commit intoPasarGuard:devfrom
kilyabin:feature/offline-grace-period
Closed

feat: add OFFLINE_GRACE_PERIOD env to extend keepAlive timeout#33
kilyabin wants to merge 1 commit intoPasarGuard:devfrom
kilyabin:feature/offline-grace-period

Conversation

@kilyabin
Copy link

@kilyabin kilyabin commented Mar 15, 2026

Adds optional OFFLINE_GRACE_PERIOD environment variable that extends the disconnect timeout beyond the panel's keepAlive value. When set, the node continues running Xray for the configured duration even if the panel becomes unreachable, instead of immediately shutting down user connections.

This improves resilience in deployments where the panel may experience temporary downtime (server restart, network issue, maintenance, etc.).


Changes

  • controller/controller.go: Modified keepAliveTracker to read OFFLINE_GRACE_PERIOD and calculate effective timeout
  • .env.example: Added documentation and example configuration

Behavior

Scenario Before After
OFFLINE_GRACE_PERIOD not set Disconnects after keepAlive timeout Same — no behavior change
OFFLINE_GRACE_PERIOD=1h Disconnects after keepAlive timeout Disconnects after keepAlive + 1h
Invalid value (e.g. OFFLINE_GRACE_PERIOD=abc) Logs warning, falls back to original keepAlive

Configuration

# .env or docker environment
OFFLINE_GRACE_PERIOD=1h

Format: Go duration string (1h, 30m, 24h, etc.)
Default: 0 (disabled — original behavior preserved)


Logging

On startup (after panel connects), the node logs:

offline grace period enabled: keepAlive=1m0s grace=5m0s effectiveTimeout=6m0s

On invalid value:

warning: invalid OFFLINE_GRACE_PERIOD value "abc": time: invalid duration "abc"

Testing

# Build locally
go build ./...

# Build Docker image
docker build -t pasarguard/node:custom .

# Run with grace period
docker run -e OFFLINE_GRACE_PERIOD=5m pasarguard/node:custom

# Test: block panel connection with iptables
sudo iptables -A INPUT -s <PANEL_IP> -p tcp --dport 62050 -j DROP

# Observe logs - disconnect should occur after keepAlive + grace period
docker logs -f pasarguard-node

# Cleanup
sudo iptables -D INPUT -s <PANEL_IP> -p tcp --dport 62050 -j DROP

Backward Compatibility

Fully backward compatible — if OFFLINE_GRACE_PERIOD is not set, behavior is identical to the original implementation.


Known Limitations

  • SyncUsers will not be called during offline period. New users added in the panel will not be synced to the node until the panel reconnects. Revoked users will remain active. This is acceptable for a failover scenario.

Checklist

  • Code compiles without errors (go build ./...)
  • Code passes vet (go vet ./...)
  • Unit tests pass (go test ./controller -v)
  • Updated .env.example
  • Backward compatibility confirmed

Summary by CodeRabbit

  • New Features
    • Added support for an optional OFFLINE_GRACE_PERIOD environment variable that extends the timeout window for disconnect detection, allowing for more graceful handling of temporary connectivity issues.

     Adds optional OFFLINE_GRACE_PERIOD environment variable that extends
     the disconnect timeout beyond the panel's keepAlive value.

     Fully backward compatible — default behavior preserved when not set.
@coderabbitai
Copy link

coderabbitai bot commented Mar 15, 2026

Walkthrough

This change adds optional offline grace period support configured through the OFFLINE_GRACE_PERIOD environment variable. The .env.example file documents this new configuration option, while controller.go implements the feature by reading the variable, parsing it as a duration, and extending the keepAlive timeout for disconnect checks when enabled.

Changes

Cohort / File(s) Summary
Configuration Documentation
.env.example
Added documentation block for new OFFLINE_GRACE_PERIOD variable, including purpose, format (Go duration string), default behavior, and commented example.
Grace Period Implementation
controller/controller.go
Added environment-driven offline grace period support that computes an effectiveTimeout by extending keepAlive with the parsed OFFLINE_GRACE_PERIOD value. Imported os package for environment variable access. Includes validation logic with warning on invalid values.

Estimated Code Review Effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 When offline moments whisper near,
A grace period grants reprieve here,
Environment whispers timings anew,
Disconnects softened through and through,
Kindness coded, config so clear!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and accurately describes the main change: adding an OFFLINE_GRACE_PERIOD environment variable to extend the keepAlive timeout, which is precisely what the changeset implements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can disable poems in the walkthrough.

Disable the reviews.poem setting to disable the poems in the walkthrough.

@kilyabin
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 15, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
controller/controller.go (1)

127-140: Consider centralizing OFFLINE_GRACE_PERIOD in config/config.go.

The implementation is functionally correct, but it reads the environment variable directly via os.Getenv() instead of following the established pattern in config/config.go where all environment variables are read through typed helper functions (GetEnv, GetEnvAsInt, GetEnvAsBool) during startup.

Benefits of centralization:

  • Consistent validation and logging at startup
  • Single source of truth in the Config struct
  • Easier to test by injecting config rather than setting env vars

However, the current approach is acceptable if runtime flexibility (reading per-connection) is desired.

♻️ Optional: Add a helper to config/config.go

Add to config/config.go:

func GetEnvAsDuration(name string, defaultVal time.Duration) time.Duration {
	valStr := GetEnv(name, "")
	if val, err := time.ParseDuration(valStr); err == nil {
		return val
	}
	return defaultVal
}

Then read in Load():

cfg.OfflineGracePeriod = GetEnvAsDuration("OFFLINE_GRACE_PERIOD", 0)

And pass it through to keepAliveTracker.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/controller.go` around lines 127 - 140, The code reads
OFFLINE_GRACE_PERIOD directly with os.Getenv inside the controller (affecting
effectiveTimeout calculation) instead of centralizing it in the Config; refactor
by adding a typed helper GetEnvAsDuration in config/config.go, load the value
into the Config (e.g., Config.OfflineGracePeriod) during Load(), and replace the
os.Getenv/time.ParseDuration block in controller.go to use the injected
cfg.OfflineGracePeriod when computing effectiveTimeout from keepAlive so env
parsing/validation and logging happen at startup and the controller uses the
typed config value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@controller/controller.go`:
- Around line 127-140: The code reads OFFLINE_GRACE_PERIOD directly with
os.Getenv inside the controller (affecting effectiveTimeout calculation) instead
of centralizing it in the Config; refactor by adding a typed helper
GetEnvAsDuration in config/config.go, load the value into the Config (e.g.,
Config.OfflineGracePeriod) during Load(), and replace the
os.Getenv/time.ParseDuration block in controller.go to use the injected
cfg.OfflineGracePeriod when computing effectiveTimeout from keepAlive so env
parsing/validation and logging happen at startup and the controller uses the
typed config value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 58ca9081-156a-4df4-992d-8681bf63fce6

📥 Commits

Reviewing files that changed from the base of the PR and between dcbcaee and 3d20f7a.

📒 Files selected for processing (2)
  • .env.example
  • controller/controller.go

@kilyabin
Copy link
Author

However, as far as I know, the panel does not automatically reconnect to the node after a prolonged downtime. This should also be addressed — otherwise the grace period only delays the problem rather than solving it. The full solution would require auto-reconnect logic on the panel side as well.

@ImMohammad20000
Copy link
Contributor

Add the new env in config package and read it from there

@M03ED
Copy link
Contributor

M03ED commented Mar 16, 2026

You can just increase keep alive instead of this

@kilyabin
Copy link
Author

You can just increase keep alive instead of this

I didn’t find in the documentation how to change or somehow manipulate this setting

@M03ED
Copy link
Contributor

M03ED commented Mar 16, 2026

IMG_20260317_022633.jpg

Just modify the node

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants