Skip to content

Draft: Probabilistic node sleection - #124

Open
utsab4u wants to merge 3 commits into
appform-io:mainfrom
utsab4u:probabilistic_node_sleection
Open

utsab4u wants to merge 3 commits into
appform-io:mainfrom
utsab4u:probabilistic_node_sleection

Conversation

@utsab4u

@utsab4u utsab4u commented Oct 3, 2026

Copy link
Copy Markdown

Description
This MR updates weighted node selection to gradually increase traffic to newly healthy instances and adds a warm-up-aware round-robin selector.
Key Changes

  • Changed two-node selection to pick probabilistically based on the sampled nodes’ weights, instead of always picking the higher-weight node.
  • Changed time-based weighting to a linear ramp from 0 to 1 over minNodeAgeMs.
  • Added WarmupRoundRobinServiceNodeSelector, which accepts candidates based on their healthy age. After a limited number of attempts, it falls back to random selection.
  • Updated iterative selection to handle zero weights and use random selection when all adjusted weights are zero.
  • Moved selector configuration and construction into Ranger through NodeSelectorConfig and ServiceNodeSelectorFactory.
  • Removed weightBoostMultiplier and fixed weighted-config builder defaults.

Why This Change?
The previous two-node comparison always preferred the higher-weight node, so gradual weight changes did not produce gradual selection probabilities. Probabilistic selection allows newly healthy instances to receive more traffic as they warm up.

Testing

  • Covered weighted selection below and above the node-count threshold.
  • Verified traffic distribution with different routing weights and healthy ages.
  • Added a warm-up round-robin distribution test.
  • Core suite: 21 tests passed.

Compatibility
Consumers must remove weightBoostMultiplier from configuration and builder calls. TimeBasedWeightEnricher now takes only the warm-up duration. Existing default node selection remains unchanged.

index = -index - 1;
final var random = ThreadLocalRandom.current();
if (totalWeight == 0.0) {
return serviceNodes.get(random.nextInt(nodeCount));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We should add log for this. It should ideally never happen

public class WeightedNodeSelectorConfig {
@JsonTypeName("weighted")
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", requireTypeIdForSubtypes = OptBoolean.FALSE)
public class WeightedNodeSelectorConfig extends NodeSelectorConfig {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Add jsonIgnore properties since you are removing field. Else it will break if someone is setting this field already

@nitishgoyal13 nitishgoyal13 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Left few comments

@sonarqubecloud

Copy link
Copy Markdown

@nitishgoyal13 nitishgoyal13 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Looks fine

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