Add progressive RealDelay probing through one Xray instance - #204
Open
eliotcougar wants to merge 8 commits into
Open
Add progressive RealDelay probing through one Xray instance#204eliotcougar wants to merge 8 commits into
eliotcougar wants to merge 8 commits into
Conversation
Drive unchanged BurstObservatory checks in bounded profile groups and publish only the affected profile result instead of repeatedly serializing complete batch snapshots.
Trust the typed v2rayNG probe plan and the fixed upstream BurstObservatory implementation instead of defending against duplicate plans, controller reuse, nil handlers, and impossible interface/result types. Remove the per-result acknowledgement barrier because the single completion consumer already serializes callbacks, while retaining bounded workers and real cancellation support.
eliotcougar
marked this pull request as ready for review
August 9, 2026 21:17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR proposes a small gomobile API for progressive RealDelay probing through one short-lived Xray instance.
It deliberately does not add or require any xray-core API. The implementation is an adapter over the existing, unchanged:
extension.BurstObservatory.Checkextension.Observatory.GetObservationrouting.BalancerPrincipleTarget.GetPrincipleTargetThe companion v2rayNG branch runs this API outside the long-running VPN process, supplies a compact combined configuration, and consumes progressive results.
Proposed API
NewProbeController()Probe(configJSON, groupsJSON, maxConcurrency, handler)ProbeController.Cancel()ProbeHandler.OnProbeResult(groupID, delay, completed)completedbecomes true after that group's last physical target.The group metadata is intentionally small: a stable caller ID, the outbound tags to check, and an optional balancer tag. Xray configuration remains ordinary JSON, so AndroidLib does not duplicate v2rayNG's profile/configuration model.
Execution model
core.NewWithContext.BurstObservatoryfeature from that instance.maxConcurrencyworkers.Check([]string{tag})once for each physical outbound target. A single-tag call is one Observatory sample regardless of least-load history settings.The configured limit therefore caps active
BurstObservatory.Checkcalls, including policy-group members. It is not merely a limit on visible UI rows.Why not create one Xray core per target concurrently?
The risk is not ordinary Go concurrency by itself. It is overlapping
*core.Instanceobjects created by multiple goroutines inside one native process.The Xray user documentation describes operational Xray instances/processes as independent, and its architecture diagram is explicitly for a single Xray process. That does not mean independently embedded
core.Instancevalues have no process-wide state.XTLS's own libXray embedding documentation now states the boundary directly: Xray-core keeps the system dialer's DNS client and outbound manager in process-wide state; creating another instance may replace them; closing the temporary instance does not restore the previous values; callers that require overlap must use separate processes.
The pinned xray-core source (
5ca6f4b7d4dc) shows why:core.New/core.NewWithContextinitialization callsinternet.InitSystemDialer.transport/internet/dialer.gostoresdnsClientandobmas package globals.InitSystemDialeroverwrites those globals with the newest instance's managers. The same global outbound manager is later used to resolvedialerProxy.Instance.Closecloses that instance's features; it does not restore the previous process-global dialer managers.Consequences of overlapping temporary instances can include a lookup or
dialerProxyoperation consulting another instance's manager, a long-running core retaining pointers replaced by a temporary test core, or process globals still referencing a manager whose instance has already closed.Serializing hundreds of independent cores would avoid overlap but retain hundreds of configuration parses, feature graphs, starts, HTTP clients, and closes. Combining compatible targets into one temporary core avoids both the state collision and most of that startup cost.
AndroidLib itself cannot create an Android process boundary. Callers must not overlap this temporary core with their long-running core in the same process. The companion v2rayNG PR runs interactive probes in a disposable
:Probeprocess and subscription probes in a process separate from the VPN daemon.Use of unchanged Burst Observatory
This adapter uses the existing Burst Observatory configuration. The upstream defaults and implementation already support HEAD requests, a five-second timeout, one-time
Checkcalls, and observation snapshots.Relevant unchanged source:
BurstObservatoryinterfaceCheckimplementationNo forked Observatory interface, notification callback, batch primitive, or deadline extension is introduced.
Failure and cancellation semantics
The app owns higher-level retry/isolation policy because only it understands profile identity and can rebuild smaller configuration subsets.
End-to-end benchmark
The benchmark exercised the companion app, so these numbers measure the complete proposal rather than this library in isolation.
Conditions:
739e303f+ AndroidLibb2138986b6fbe5e5+ AndroidLib484a8771Values are medians of three runs:
All six measured runs completed every target without crashes, ANRs, probe failures, or timeouts. The 3.330-second HTTP phase is close to the 3.125-second theoretical floor for 500 targets, 16 workers, and 100 ms responses.
Boundaries
5 s * ceil(500 / 16) = 160 s.Validation
go test -race ./...go vet ./...ProbeControllerandProbeHandlerThe focused test file is retained locally for continued development but is intentionally not included in this PR diff.
Companion integration
v2rayNG draft PR: 2dust/v2rayNG#6050.
The companion PR documents profile-plan construction, process isolation, fallback handling, UI result coalescing, and the UI-specific benchmark.