Search in sources :

Example 21 with Context

use of io.mantisrx.runtime.Context in project mantis by Netflix.

the class JobAutoScalerTest method testScaleUpOnDifferentScalingReasons.

@Test
public void testScaleUpOnDifferentScalingReasons() throws InterruptedException {
    final List<StageScalingPolicy.ScalingReason> scalingReasons = Arrays.asList(DataDrop, KafkaLag, UserDefined);
    for (StageScalingPolicy.ScalingReason scalingReason : scalingReasons) {
        logger.info("==== test scaling reason {} =====", scalingReason.name());
        final String jobId = "test-job-1";
        final int coolDownSec = 2;
        final int scalingStageNum = 1;
        final MantisMasterClientApi mockMasterClientApi = mock(MantisMasterClientApi.class);
        final Map<Integer, StageSchedulingInfo> schedulingInfoMap = new HashMap<>();
        final int numStage1Workers = 1;
        final int increment = 1;
        final int decrement = 0;
        final int min = 1;
        final int max = 5;
        final double scaleUpAbove = 2000.0;
        final double scaleDownBelow = 0.0;
        final double workerMemoryMB = 512.0;
        final StageSchedulingInfo stage1SchedInfo = StageSchedulingInfo.builder().numberOfInstances(numStage1Workers).machineDefinition(new MachineDefinition(2, workerMemoryMB, 200, 1024, 2)).scalingPolicy(new StageScalingPolicy(scalingStageNum, min, max, increment, decrement, coolDownSec, Collections.singletonMap(scalingReason, new StageScalingPolicy.Strategy(scalingReason, scaleDownBelow, scaleUpAbove, new StageScalingPolicy.RollingCount(1, 2))))).scalable(true).build();
        schedulingInfoMap.put(scalingStageNum, stage1SchedInfo);
        when(mockMasterClientApi.scaleJobStage(eq(jobId), eq(scalingStageNum), eq(numStage1Workers + increment), anyString())).thenReturn(Observable.just(true));
        Context context = mock(Context.class);
        when(context.getWorkerMapObservable()).thenReturn(Observable.empty());
        final JobAutoScaler jobAutoScaler = new JobAutoScaler(jobId, new SchedulingInfo(schedulingInfoMap), mockMasterClientApi, context);
        jobAutoScaler.start();
        final Observer<JobAutoScaler.Event> jobAutoScalerObserver = jobAutoScaler.getObserver();
        // should trigger a scale up (above scaleUp threshold)
        jobAutoScalerObserver.onNext(new JobAutoScaler.Event(scalingReason, scalingStageNum, scaleUpAbove + 0.01, numStage1Workers, ""));
        verify(mockMasterClientApi, timeout(1000).times(1)).scaleJobStage(jobId, scalingStageNum, numStage1Workers + increment, String.format("%s with value %2$.2f exceeded scaleUp threshold of %3$.1f", scalingReason.name(), (scaleUpAbove + 0.01), scaleUpAbove));
        // should *not* trigger a scale up before cooldown period (above scaleUp threshold)
        jobAutoScalerObserver.onNext(new JobAutoScaler.Event(scalingReason, scalingStageNum, scaleUpAbove + 0.01, numStage1Workers + increment, ""));
        jobAutoScalerObserver.onNext(new JobAutoScaler.Event(scalingReason, scalingStageNum, scaleUpAbove + 0.01, numStage1Workers + increment, ""));
        Thread.sleep(coolDownSec * 1000);
        // retry sending auto scale event till scaleJobStage request sent to master, as there is possible a race between the sleep for coolDownSecs in the Test and the event being processed before coolDownSecs
        final CountDownLatch retryLatch = new CountDownLatch(1);
        when(mockMasterClientApi.scaleJobStage(eq(jobId), eq(scalingStageNum), eq(numStage1Workers + 2 * increment), anyString())).thenAnswer(new Answer<Observable<Void>>() {

            @Override
            public Observable<Void> answer(InvocationOnMock invocation) throws Throwable {
                retryLatch.countDown();
                return Observable.just(null);
            }
        });
        do {
            logger.info("sending Job auto scale Event");
            // should trigger a scale up after cooldown period (above scaleUp threshold)
            jobAutoScalerObserver.onNext(new JobAutoScaler.Event(scalingReason, scalingStageNum, scaleUpAbove + 0.01, numStage1Workers + increment, ""));
        } while (!retryLatch.await(1, TimeUnit.SECONDS));
        verify(mockMasterClientApi, timeout(1000).times(1)).scaleJobStage(jobId, scalingStageNum, numStage1Workers + 2 * increment, String.format("%s with value %2$.2f exceeded scaleUp threshold of %3$.1f", scalingReason.name(), (scaleUpAbove + 0.01), scaleUpAbove));
    }
}
Also used : HashMap(java.util.HashMap) Matchers.anyString(org.mockito.Matchers.anyString) MantisMasterClientApi(io.mantisrx.server.master.client.MantisMasterClientApi) Context(io.mantisrx.runtime.Context) MachineDefinition(io.mantisrx.runtime.MachineDefinition) StageSchedulingInfo(io.mantisrx.runtime.descriptor.StageSchedulingInfo) SchedulingInfo(io.mantisrx.runtime.descriptor.SchedulingInfo) CountDownLatch(java.util.concurrent.CountDownLatch) Observable(rx.Observable) StageScalingPolicy(io.mantisrx.runtime.descriptor.StageScalingPolicy) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) InvocationOnMock(org.mockito.invocation.InvocationOnMock) StageSchedulingInfo(io.mantisrx.runtime.descriptor.StageSchedulingInfo) Test(org.junit.Test)

Example 22 with Context

use of io.mantisrx.runtime.Context in project mantis by Netflix.

the class JobAutoScalerTest method testScalingResiliency.

@Test
public void testScalingResiliency() throws InterruptedException {
    final String jobId = "test-job-1";
    final int coolDownSec = 2;
    final int scalingStageNum = 1;
    final MantisMasterClientApi mockMasterClientApi = mock(MantisMasterClientApi.class);
    final Map<Integer, StageSchedulingInfo> schedulingInfoMap = new HashMap<>();
    final int numStage1Workers = 1;
    final int increment = 1;
    final int decrement = 1;
    final int min = 1;
    final int max = 5;
    final double scaleUpAbovePct = 45.0;
    final double scaleDownBelowPct = 15.0;
    final double workerMemoryMB = 512.0;
    final StageSchedulingInfo stage1SchedInfo = StageSchedulingInfo.builder().numberOfInstances(numStage1Workers).machineDefinition(new MachineDefinition(2, workerMemoryMB, 200, 1024, 2)).scalingPolicy(new StageScalingPolicy(scalingStageNum, min, max, increment, decrement, coolDownSec, Collections.singletonMap(StageScalingPolicy.ScalingReason.Memory, new StageScalingPolicy.Strategy(StageScalingPolicy.ScalingReason.Memory, scaleDownBelowPct, scaleUpAbovePct, new StageScalingPolicy.RollingCount(1, 2))))).scalable(true).build();
    schedulingInfoMap.put(scalingStageNum, stage1SchedInfo);
    final CountDownLatch scaleJobStageSuccessLatch = new CountDownLatch(1);
    final AtomicInteger count = new AtomicInteger(0);
    final Observable<Boolean> simulateScaleJobStageFailureResp = Observable.just(1).map(new Func1<Integer, Boolean>() {

        @Override
        public Boolean call(Integer integer) {
            if (count.incrementAndGet() < 3) {
                throw new IllegalStateException("fake connection exception");
            } else {
                scaleJobStageSuccessLatch.countDown();
                return true;
            }
        }
    });
    when(mockMasterClientApi.scaleJobStage(eq(jobId), eq(scalingStageNum), eq(numStage1Workers + increment), anyString())).thenReturn(simulateScaleJobStageFailureResp);
    Context context = mock(Context.class);
    when(context.getWorkerMapObservable()).thenReturn(Observable.empty());
    final JobAutoScaler jobAutoScaler = new JobAutoScaler(jobId, new SchedulingInfo(schedulingInfoMap), mockMasterClientApi, context);
    jobAutoScaler.start();
    final Observer<JobAutoScaler.Event> jobAutoScalerObserver = jobAutoScaler.getObserver();
    // should trigger a scale up (above 45% scaleUp threshold)
    jobAutoScalerObserver.onNext(new JobAutoScaler.Event(StageScalingPolicy.ScalingReason.Memory, scalingStageNum, workerMemoryMB * (scaleUpAbovePct / 100.0 + 0.01), numStage1Workers, ""));
    verify(mockMasterClientApi, timeout(1000).times(1)).scaleJobStage(jobId, scalingStageNum, numStage1Workers + increment, String.format("Memory with value %1$,.2f exceeded scaleUp threshold of 45.0", (scaleUpAbovePct / 100.0 + 0.01) * 100.0));
    scaleJobStageSuccessLatch.await();
}
Also used : HashMap(java.util.HashMap) Matchers.anyString(org.mockito.Matchers.anyString) MantisMasterClientApi(io.mantisrx.server.master.client.MantisMasterClientApi) Context(io.mantisrx.runtime.Context) MachineDefinition(io.mantisrx.runtime.MachineDefinition) StageSchedulingInfo(io.mantisrx.runtime.descriptor.StageSchedulingInfo) SchedulingInfo(io.mantisrx.runtime.descriptor.SchedulingInfo) CountDownLatch(java.util.concurrent.CountDownLatch) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) StageScalingPolicy(io.mantisrx.runtime.descriptor.StageScalingPolicy) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) StageSchedulingInfo(io.mantisrx.runtime.descriptor.StageSchedulingInfo) Test(org.junit.Test)

Example 23 with Context

use of io.mantisrx.runtime.Context in project mantis by Netflix.

the class StageExecutorsSingleStageTest method testSingleStageJob.

@SuppressWarnings("rawtypes")
@Test
public void testSingleStageJob() {
    Action0 noOpAction = new Action0() {

        @Override
        public void call() {
        }
    };
    Action1<Throwable> noOpError = new Action1<Throwable>() {

        @Override
        public void call(Throwable t) {
        }
    };
    TestJobSingleStage provider = new TestJobSingleStage();
    Job job = provider.getJobInstance();
    PortSelector portSelector = new PortSelectorInRange(8000, 9000);
    StageConfig<?, ?> stage = (StageConfig<?, ?>) job.getStages().get(0);
    BehaviorSubject<Integer> workersInStageOneObservable = BehaviorSubject.create(1);
    StageExecutors.executeSingleStageJob(job.getSource(), stage, job.getSink(), portSelector, new RxMetrics(), new Context(), noOpAction, 0, workersInStageOneObservable, null, null, noOpAction, noOpError);
    Iterator<Integer> iter = provider.getItemsWritten().iterator();
    Assert.assertEquals(0, iter.next().intValue());
    Assert.assertEquals(1, iter.next().intValue());
    Assert.assertEquals(4, iter.next().intValue());
    Assert.assertEquals(9, iter.next().intValue());
}
Also used : Context(io.mantisrx.runtime.Context) Action0(rx.functions.Action0) Action1(rx.functions.Action1) StageConfig(io.mantisrx.runtime.StageConfig) RxMetrics(io.reactivex.mantis.remote.observable.RxMetrics) Job(io.mantisrx.runtime.Job) Test(org.junit.Test)

Example 24 with Context

use of io.mantisrx.runtime.Context in project mantis by Netflix.

the class TestJobParameterized method getJobInstance.

@Override
public Job<Integer> getJobInstance() {
    return MantisJob.<Integer>source(new Source<Integer>() {

        @Override
        public Observable<Observable<Integer>> call(Context context, Index index) {
            Integer start = (Integer) context.getParameters().get("start-range");
            Integer end = (Integer) context.getParameters().get("end-range");
            return Observable.just(Observable.range(start, end));
        }
    }).stage(new ScalarComputation<Integer, Integer>() {

        @Override
        public Observable<Integer> call(Context context, Observable<Integer> t1) {
            final Integer scale = (Integer) context.getParameters().get("scale-by");
            return t1.map(new Func1<Integer, Integer>() {

                @Override
                public Integer call(Integer t1) {
                    return t1 * scale;
                }
            });
        }
    }, new ScalarToScalar.Config<Integer, Integer>().codec(Codecs.integer())).sink(new Sink<Integer>() {

        @Override
        public void init(Context context) {
            System.out.println("sink init called");
        }

        @Override
        public void call(Context context, PortRequest p, Observable<Integer> o) {
            final String message = (String) context.getParameters().get("sink-message");
            o.toBlocking().forEach(new Action1<Integer>() {

                @Override
                public void call(Integer t1) {
                    System.out.println(message + t1);
                    itemsWritten.add(t1);
                }
            });
        }
    }).metadata(new Metadata.Builder().name("test job").description("showcase parameters").build()).parameterDefinition(new IntParameter().name("start-range").validator(Validators.range(0, 100)).build()).parameterDefinition(new IntParameter().name("end-range").validator(Validators.range(100, 1000)).build()).parameterDefinition(new IntParameter().name("scale-by").description("scale each value from the range").validator(Validators.range(1, 10)).build()).parameterDefinition(new StringParameter().name("sink-message").defaultValue("hello: ").description("concat with results").validator(Validators.notNullOrEmpty()).build()).create();
}
Also used : Context(io.mantisrx.runtime.Context) StringParameter(io.mantisrx.runtime.parameter.type.StringParameter) Action1(rx.functions.Action1) Metadata(io.mantisrx.runtime.Metadata) Index(io.mantisrx.runtime.source.Index) Observable(rx.Observable) ScalarToScalar(io.mantisrx.runtime.ScalarToScalar) PortRequest(io.mantisrx.runtime.PortRequest) ScalarComputation(io.mantisrx.runtime.computation.ScalarComputation) IntParameter(io.mantisrx.runtime.parameter.type.IntParameter)

Example 25 with Context

use of io.mantisrx.runtime.Context in project mantis by Netflix.

the class ContextualHttpSourceTest method canStreamFromMultipleServersWithCorrectContext.

@Test
public void canStreamFromMultipleServersWithCorrectContext() throws Exception {
    ContextualHttpSource<ServerSentEvent> source = HttpSources.contextualSource(HttpClientFactories.sseClientFactory(), HttpRequestFactories.createGetFactory("test/stream")).withServerProvider(localServerProvider).withActivityObserver(sourceObserver).build();
    final AtomicInteger counter = new AtomicInteger();
    final CountDownLatch done = new CountDownLatch(1);
    final ConcurrentHashMap<String, AtomicInteger> result = new ConcurrentHashMap<>();
    final CopyOnWriteArraySet<ServerInfo> connectedServers = new CopyOnWriteArraySet<>();
    Observable.merge(source.call(new Context(), new Index(1, 1))).doOnNext(new Action1<ServerContext<ServerSentEvent>>() {

        @Override
        public void call(ServerContext<ServerSentEvent> pair) {
            assertTrue(pair.getValue().contentAsString().contains("line"));
            counter.incrementAndGet();
            String msg = pair.getValue().contentAsString();
            result.putIfAbsent(msg, new AtomicInteger());
            result.get(msg).incrementAndGet();
            connectedServers.add(pair.getServer());
        }
    }).doOnError(new Action1<Throwable>() {

        @Override
        public void call(Throwable throwable) {
            fail("Unexpected failure: " + throwable);
        }
    }).doOnCompleted(new Action0() {

        @Override
        public void call() {
            System.out.println("completed");
        }
    }).doAfterTerminate(new Action0() {

        @Override
        public void call() {
            done.countDown();
        }
    }).subscribe();
    long waitSeconds = 3;
    boolean timedout = !done.await(waitSeconds, TimeUnit.SECONDS);
    if (timedout) {
        fail(String.format("Waited at least %d seconds for the test to finish. Something is wrong", waitSeconds));
    }
    assertEquals("There should be as many as provided servers", localServerProvider.serverSize(), connectedServers.size());
    Assert.assertEquals(String.format("%d servers => the result has %d times of a single stream", localServerProvider.serverSize(), localServerProvider.serverSize()), counter.get(), RequestProcessor.smallStreamContent.size() * localServerProvider.serverSize());
    for (String data : RequestProcessor.smallStreamContent) {
        assertEquals(String.format("%d servers => %d identical copies per message", localServerProvider.serverSize(), localServerProvider.serverSize()), localServerProvider.serverSize(), result.get(data).get());
    }
    for (ServerInfo server : localServerProvider.getServerInfos()) {
        assertEquals("There should be one completion per server", 1, sourceObserver.getCount(server, EventType.SOURCE_COMPLETED));
        assertEquals("There should be one un-subscription per server", 1, sourceObserver.getCount(server, EventType.CONNECTION_UNSUBSCRIBED));
        assertEquals("There should be no error", 0, sourceObserver.getCount(server, EventType.SUBSCRIPTION_FAILED));
        assertEquals("There should be one connection per server", 1, sourceObserver.getCount(server, EventType.CONNECTION_ESTABLISHED));
    }
    assertEquals("There should be one completions", 1, sourceObserver.getCompletionCount());
    assertEquals(0, sourceObserver.getErrorCount());
    Set<EventType> events = sourceObserver.getEvents();
    assertEquals(EXPECTED_EVENTS_SETS, events);
    for (EventType event : events) {
        assertEquals("Each event should be recorded exactly once per server", localServerProvider.serverSize(), sourceObserver.getEventCount(event));
    }
}
Also used : Context(io.mantisrx.runtime.Context) ServerContext(io.mantisrx.runtime.source.http.impl.ServerContext) Action0(rx.functions.Action0) Action1(rx.functions.Action1) EventType(io.mantisrx.runtime.source.http.impl.HttpSourceImpl.HttpSourceEvent.EventType) ServerInfo(mantis.io.reactivex.netty.client.RxClient.ServerInfo) ServerSentEvent(mantis.io.reactivex.netty.protocol.http.sse.ServerSentEvent) Index(io.mantisrx.runtime.source.Index) CopyOnWriteArraySet(java.util.concurrent.CopyOnWriteArraySet) CountDownLatch(java.util.concurrent.CountDownLatch) ServerContext(io.mantisrx.runtime.source.http.impl.ServerContext) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Test(org.junit.Test)

Aggregations

Context (io.mantisrx.runtime.Context)49 Test (org.junit.Test)34 CountDownLatch (java.util.concurrent.CountDownLatch)24 Index (io.mantisrx.runtime.source.Index)23 Observable (rx.Observable)23 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)20 Action1 (rx.functions.Action1)19 Action0 (rx.functions.Action0)17 Map (java.util.Map)16 Parameters (io.mantisrx.runtime.parameter.Parameters)15 Logger (org.slf4j.Logger)13 LoggerFactory (org.slf4j.LoggerFactory)13 ParameterTestUtils (io.mantisrx.connector.kafka.ParameterTestUtils)11 TimeUnit (java.util.concurrent.TimeUnit)11 StageConfig (io.mantisrx.runtime.StageConfig)10 HashMap (java.util.HashMap)10 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)10 Endpoint (io.mantisrx.common.network.Endpoint)9 WorkerInfo (io.mantisrx.runtime.WorkerInfo)9 ByteBuf (io.netty.buffer.ByteBuf)8