Search in sources :

Example 1 with NoOpDarkClusterStrategy

use of com.linkedin.darkcluster.api.NoOpDarkClusterStrategy in project rest.li by linkedin.

the class TestDarkClusterStrategyFactory method testCreateStrategiesWithNoDarkClusters.

@Test
public void testCreateStrategiesWithNoDarkClusters() {
    DarkClusterStrategy strategy = _strategyFactory.get(DARK_CLUSTER_NAME);
    RestRequest dummyRestRequest = new RestRequestBuilder(URI.create("foo")).build();
    boolean requestSent = strategy.handleRequest(dummyRestRequest, dummyRestRequest, new RequestContext());
    Assert.assertTrue(strategy instanceof NoOpDarkClusterStrategy);
    Assert.assertFalse(requestSent, "default empty strategy should not send request");
}
Also used : RestRequest(com.linkedin.r2.message.rest.RestRequest) NoOpDarkClusterStrategy(com.linkedin.darkcluster.api.NoOpDarkClusterStrategy) RelativeTrafficMultiplierDarkClusterStrategy(com.linkedin.darkcluster.impl.RelativeTrafficMultiplierDarkClusterStrategy) DarkClusterStrategy(com.linkedin.darkcluster.api.DarkClusterStrategy) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) RequestContext(com.linkedin.r2.message.RequestContext) NoOpDarkClusterStrategy(com.linkedin.darkcluster.api.NoOpDarkClusterStrategy) Test(org.testng.annotations.Test)

Example 2 with NoOpDarkClusterStrategy

use of com.linkedin.darkcluster.api.NoOpDarkClusterStrategy in project rest.li by linkedin.

the class TestDarkClusterStrategyFactory method testStrategyFallThruWithNoFallback.

@Test
public void testStrategyFallThruWithNoFallback() {
    DarkClusterConfig darkClusterConfig1 = createRelativeTrafficMultiplierConfig(0.5f);
    DarkClusterStrategyNameArray darkClusterStrategyList = new DarkClusterStrategyNameArray();
    // Only ConstantQPS strategy is present, with no alternative.
    darkClusterStrategyList.addAll(Collections.singletonList(CONSTANT_QPS));
    darkClusterConfig1.setDarkClusterStrategyPrioritizedList(darkClusterStrategyList);
    _clusterInfoProvider.addDarkClusterConfig(SOURCE_CLUSTER_NAME, DARK_CLUSTER_NAME, darkClusterConfig1);
    _clusterInfoProvider.notifyListenersClusterAdded(SOURCE_CLUSTER_NAME);
    DarkClusterStrategy strategy = _strategyFactory.get(DARK_CLUSTER_NAME);
    // test that we didn't find a strategy corresponding to Constant QPS and fell through. It will end up with the NoOpStrategy.
    Assert.assertTrue(strategy instanceof NoOpDarkClusterStrategy);
}
Also used : DarkClusterStrategyNameArray(com.linkedin.d2.DarkClusterStrategyNameArray) DarkClusterConfig(com.linkedin.d2.DarkClusterConfig) NoOpDarkClusterStrategy(com.linkedin.darkcluster.api.NoOpDarkClusterStrategy) RelativeTrafficMultiplierDarkClusterStrategy(com.linkedin.darkcluster.impl.RelativeTrafficMultiplierDarkClusterStrategy) DarkClusterStrategy(com.linkedin.darkcluster.api.DarkClusterStrategy) NoOpDarkClusterStrategy(com.linkedin.darkcluster.api.NoOpDarkClusterStrategy) Test(org.testng.annotations.Test)

Example 3 with NoOpDarkClusterStrategy

use of com.linkedin.darkcluster.api.NoOpDarkClusterStrategy in project rest.li by linkedin.

the class TestDarkClusterStrategyFactory method testStrategyZeroMultiplier.

@Test
public void testStrategyZeroMultiplier() {
    DarkClusterConfig darkClusterConfig1 = createRelativeTrafficMultiplierConfig(0f);
    DarkClusterStrategyNameArray darkClusterStrategyList = new DarkClusterStrategyNameArray();
    darkClusterStrategyList.addAll(Collections.singletonList(RELATIVE_TRAFFIC));
    darkClusterConfig1.setDarkClusterStrategyPrioritizedList(darkClusterStrategyList);
    _clusterInfoProvider.addDarkClusterConfig(SOURCE_CLUSTER_NAME, DARK_CLUSTER_NAME, darkClusterConfig1);
    DarkClusterStrategy strategy = _strategyFactory.get(DARK_CLUSTER_NAME);
    // test that we choose a NoOpDarkClusterStrategy because we want to allow RelativeTrafficMultiplierStrategy with a zero muliplier to be
    // a NoOp. This allows clients to easily turn off traffic without adjusting multiple values.
    Assert.assertTrue(strategy instanceof NoOpDarkClusterStrategy);
}
Also used : DarkClusterStrategyNameArray(com.linkedin.d2.DarkClusterStrategyNameArray) DarkClusterConfig(com.linkedin.d2.DarkClusterConfig) NoOpDarkClusterStrategy(com.linkedin.darkcluster.api.NoOpDarkClusterStrategy) RelativeTrafficMultiplierDarkClusterStrategy(com.linkedin.darkcluster.impl.RelativeTrafficMultiplierDarkClusterStrategy) DarkClusterStrategy(com.linkedin.darkcluster.api.DarkClusterStrategy) NoOpDarkClusterStrategy(com.linkedin.darkcluster.api.NoOpDarkClusterStrategy) Test(org.testng.annotations.Test)

Example 4 with NoOpDarkClusterStrategy

use of com.linkedin.darkcluster.api.NoOpDarkClusterStrategy in project rest.li by linkedin.

the class TestDarkClusterStrategyFactory method testStrategyRaceCondition.

@Test
public void testStrategyRaceCondition() {
    int noopStrategyCount = 0;
    DarkClusterConfig darkClusterConfig1 = createRelativeTrafficMultiplierConfig(0.5f);
    _clusterInfoProvider.addDarkClusterConfig(SOURCE_CLUSTER_NAME, DARK_CLUSTER_NAME, darkClusterConfig1);
    _clusterInfoProvider.notifyListenersClusterAdded(SOURCE_CLUSTER_NAME);
    DarkClusterStrategy strategy = _strategyFactory.get(DARK_CLUSTER_NAME);
    Assert.assertTrue(strategy instanceof RelativeTrafficMultiplierDarkClusterStrategy);
    Assert.assertEquals(((RelativeTrafficMultiplierDarkClusterStrategy) strategy).getMultiplier(), 0.5f, "expected 0.5f multiplier");
    // this was registered after DarkClusterStrategyFactoryImpl registered it's clusterListener.
    _clusterInfoProvider.registerClusterListener(new DeletingClusterListener(_clusterInfoProvider));
    ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
    final CountDownLatch latch = new CountDownLatch(1);
    try {
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            _clusterInfoProvider.notifyListenersClusterAdded(SOURCE_CLUSTER_NAME);
            latch.countDown();
        }, 0, 1, TimeUnit.MILLISECONDS);
        if (!latch.await(30, TimeUnit.SECONDS)) {
            fail("unable to execute task on executor");
        }
        for (int i = 0; i < 100000; i++) {
            strategy = _strategyFactory.get(DARK_CLUSTER_NAME);
            // verified that this will catch race conditions, saw it happen 9/100k times.
            Assert.assertNotNull(strategy, "null at iteration: " + i);
            if (strategy instanceof NoOpDarkClusterStrategy) {
                noopStrategyCount++;
            }
        }
        System.out.println("noopStrategyCount: " + noopStrategyCount);
    } catch (InterruptedException ie) {
        fail("got interrupted exception", ie);
    } finally {
        scheduledExecutorService.shutdown();
    }
}
Also used : ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) RelativeTrafficMultiplierDarkClusterStrategy(com.linkedin.darkcluster.impl.RelativeTrafficMultiplierDarkClusterStrategy) DarkClusterConfig(com.linkedin.d2.DarkClusterConfig) NoOpDarkClusterStrategy(com.linkedin.darkcluster.api.NoOpDarkClusterStrategy) RelativeTrafficMultiplierDarkClusterStrategy(com.linkedin.darkcluster.impl.RelativeTrafficMultiplierDarkClusterStrategy) DarkClusterStrategy(com.linkedin.darkcluster.api.DarkClusterStrategy) CountDownLatch(java.util.concurrent.CountDownLatch) NoOpDarkClusterStrategy(com.linkedin.darkcluster.api.NoOpDarkClusterStrategy) Test(org.testng.annotations.Test)

Example 5 with NoOpDarkClusterStrategy

use of com.linkedin.darkcluster.api.NoOpDarkClusterStrategy in project rest.li by linkedin.

the class DarkClusterStrategyFactoryImpl method createStrategy.

/**
 * In the future, additional strategies can be added, and the logic here can choose the appropriate one based on the config values.
 */
private DarkClusterStrategy createStrategy(String darkClusterName, DarkClusterConfig darkClusterConfig) {
    if (darkClusterConfig.hasDarkClusterStrategyPrioritizedList()) {
        DarkClusterStrategyNameArray strategyList = darkClusterConfig.getDarkClusterStrategyPrioritizedList();
        for (com.linkedin.d2.DarkClusterStrategyName darkClusterStrategyName : strategyList) {
            switch(darkClusterStrategyName) {
                case RELATIVE_TRAFFIC:
                    if (RelativeTrafficMultiplierDarkClusterStrategy.isValidConfig(darkClusterConfig)) {
                        BaseDarkClusterDispatcher baseDarkClusterDispatcher = new BaseDarkClusterDispatcherImpl(darkClusterName, _darkClusterDispatcher, _notifier, _verifierManager);
                        return new RelativeTrafficMultiplierDarkClusterStrategy(_sourceClusterName, darkClusterName, darkClusterConfig.getMultiplier(), baseDarkClusterDispatcher, _notifier, _facilities.getClusterInfoProvider(), _random);
                    }
                    break;
                case IDENTICAL_TRAFFIC:
                    if (IdenticalTrafficMultiplierDarkClusterStrategy.isValidConfig(darkClusterConfig)) {
                        BaseDarkClusterDispatcher baseDarkClusterDispatcher = new BaseDarkClusterDispatcherImpl(darkClusterName, _darkClusterDispatcher, _notifier, _verifierManager);
                        return new IdenticalTrafficMultiplierDarkClusterStrategy(_sourceClusterName, darkClusterName, darkClusterConfig.getMultiplier(), baseDarkClusterDispatcher, _notifier, _facilities.getClusterInfoProvider(), _random);
                    }
                    break;
                case CONSTANT_QPS:
                    if (_rateLimiterSupplier == null) {
                        LOG.error("Dark Cluster {} configured to use CONSTANT_QPS strategy, but no rate limiter provided during instantiation. " + "No Dark Cluster strategy will be used!", darkClusterName);
                        break;
                    }
                    if (ConstantQpsDarkClusterStrategy.isValidConfig(darkClusterConfig)) {
                        BaseDarkClusterDispatcher baseDarkClusterDispatcher = new BaseDarkClusterDispatcherImpl(darkClusterName, _darkClusterDispatcher, _notifier, _verifierManager);
                        ConstantQpsRateLimiter rateLimiter = _rateLimiterSupplier.get();
                        rateLimiter.setBufferCapacity(darkClusterConfig.getDispatcherMaxRequestsToBuffer());
                        rateLimiter.setBufferTtl(darkClusterConfig.getDispatcherBufferedRequestExpiryInSeconds(), ChronoUnit.SECONDS);
                        return new ConstantQpsDarkClusterStrategy(_sourceClusterName, darkClusterName, darkClusterConfig.getDispatcherOutboundTargetRate(), baseDarkClusterDispatcher, _notifier, _facilities.getClusterInfoProvider(), rateLimiter);
                    }
                    break;
                default:
                    break;
            }
        }
    }
    return new NoOpDarkClusterStrategy();
}
Also used : ConstantQpsRateLimiter(com.linkedin.r2.transport.http.client.ConstantQpsRateLimiter) DarkClusterStrategyNameArray(com.linkedin.d2.DarkClusterStrategyNameArray) BaseDarkClusterDispatcher(com.linkedin.darkcluster.api.BaseDarkClusterDispatcher) NoOpDarkClusterStrategy(com.linkedin.darkcluster.api.NoOpDarkClusterStrategy)

Aggregations

NoOpDarkClusterStrategy (com.linkedin.darkcluster.api.NoOpDarkClusterStrategy)5 DarkClusterStrategy (com.linkedin.darkcluster.api.DarkClusterStrategy)4 RelativeTrafficMultiplierDarkClusterStrategy (com.linkedin.darkcluster.impl.RelativeTrafficMultiplierDarkClusterStrategy)4 Test (org.testng.annotations.Test)4 DarkClusterConfig (com.linkedin.d2.DarkClusterConfig)3 DarkClusterStrategyNameArray (com.linkedin.d2.DarkClusterStrategyNameArray)3 BaseDarkClusterDispatcher (com.linkedin.darkcluster.api.BaseDarkClusterDispatcher)1 RequestContext (com.linkedin.r2.message.RequestContext)1 RestRequest (com.linkedin.r2.message.rest.RestRequest)1 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)1 ConstantQpsRateLimiter (com.linkedin.r2.transport.http.client.ConstantQpsRateLimiter)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 ScheduledExecutorService (java.util.concurrent.ScheduledExecutorService)1