@Override
    public LoadBalancer<Endpoint, ClientRequestContext> newLoadBalancer(
            @Nullable LoadBalancer<Endpoint, ClientRequestContext> oldLoadBalancer, List<Endpoint> candidates) {
        if (oldLoadBalancer == null) {
            final UpdatableLoadBalancer<Endpoint> newLoadBalancer =
                    LoadBalancer.builderForRampingUp(candidates)
                                .rampingUpIntervalMillis(rampingUpIntervalMillis)
                                .rampingUpTaskWindowMillis(rampingUpTaskWindowMillis)
                                .totalSteps(totalSteps)
                                .weightTransition(weightTransition)
                                .timestampFunction(timestampFunction)
                                .executor(executorSupplier.get())
                                .ticker(ticker)
                                .build();
            return unsafeCast(newLoadBalancer);
        } else {
            assert oldLoadBalancer instanceof UpdatableLoadBalancer;
            @SuppressWarnings("unchecked")
            final UpdatableLoadBalancer<Endpoint> casted =
                    (UpdatableLoadBalancer<Endpoint>) (LoadBalancer<Endpoint, ?>) oldLoadBalancer;
            casted.updateCandidates(candidates);
            return unsafeCast(casted);
        }
    }
A ramping up {@link EndpointSelectionStrategy} which ramps the weight of newly added
{@link Endpoint}s using {@link WeightTransition},
{@code rampingUpIntervalMillis} and {@code rampingUpTaskWindow}.
If more than one {@link Endpoint} are added within the {@code rampingUpTaskWindow}, the weights of
them are updated together. If there's already a scheduled job and new {@link Endpoint}s are added
within the {@code rampingUpTaskWindow}, they are updated together.
This is an example of how it works when {@code rampingUpTaskWindow} is 500 milliseconds and
{@code rampingUpIntervalMillis} is 2000 milliseconds:
<pre>{@code
----------------------------------------------------------------------------------------------------
    A         B                             C                                       D
    t0        t1                            t2                                      t3         t4
----------------------------------------------------------------------------------------------------
    0ms       t0 + 200ms                    t0 + 1000ms                          t0 + 1800ms  t0 + 2000ms
}</pre>
A and B are ramped up right away when they are added and they are ramped up together at t4.
C is updated alone every 2000 milliseconds. D is ramped up together with A and B at t4.
core/src/main/java/com/linecorp/armeria/client/endpoint/WeightRampingUpStrategy.java