Search in sources :

Example 41 with Context

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

the class JobAutoScalerTest method testScaleUp.

@Test
public void testScaleUp() 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);
    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 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));
    // should *not* trigger a scale up before cooldown period (above 45% scaleUp threshold)
    jobAutoScalerObserver.onNext(new JobAutoScaler.Event(StageScalingPolicy.ScalingReason.Memory, scalingStageNum, workerMemoryMB * (scaleUpAbovePct / 100.0 + 0.01), numStage1Workers + increment, ""));
    jobAutoScalerObserver.onNext(new JobAutoScaler.Event(StageScalingPolicy.ScalingReason.Memory, scalingStageNum, workerMemoryMB * (scaleUpAbovePct / 100.0 + 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 45% scaleUp threshold)
        jobAutoScalerObserver.onNext(new JobAutoScaler.Event(StageScalingPolicy.ScalingReason.Memory, scalingStageNum, workerMemoryMB * (scaleUpAbovePct / 100.0 + 0.01), numStage1Workers + increment, ""));
    } while (!retryLatch.await(1, TimeUnit.SECONDS));
    verify(mockMasterClientApi, timeout(1000).times(1)).scaleJobStage(jobId, scalingStageNum, numStage1Workers + 2 * increment, String.format("Memory with value %1$,.2f exceeded scaleUp threshold of 45.0", (scaleUpAbovePct / 100.0 + 0.01) * 100.0));
}
Also used : Context(io.mantisrx.runtime.Context) MachineDefinition(io.mantisrx.runtime.MachineDefinition) StageSchedulingInfo(io.mantisrx.runtime.descriptor.StageSchedulingInfo) SchedulingInfo(io.mantisrx.runtime.descriptor.SchedulingInfo) HashMap(java.util.HashMap) Matchers.anyString(org.mockito.Matchers.anyString) CountDownLatch(java.util.concurrent.CountDownLatch) Observable(rx.Observable) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) StageScalingPolicy(io.mantisrx.runtime.descriptor.StageScalingPolicy) MantisMasterClientApi(io.mantisrx.server.master.client.MantisMasterClientApi) InvocationOnMock(org.mockito.invocation.InvocationOnMock) StageSchedulingInfo(io.mantisrx.runtime.descriptor.StageSchedulingInfo) Test(org.junit.Test)

Example 42 with Context

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

the class IcebergWriterStageTest method setUp.

@BeforeEach
void setUp() {
    record = GenericRecord.create(SCHEMA);
    record.setField("id", 1);
    this.scheduler = new TestScheduler();
    this.subscriber = new TestSubscriber<>();
    // Writer
    Parameters parameters = StageOverrideParameters.newParameters();
    WriterConfig config = new WriterConfig(parameters, mock(Configuration.class));
    WriterMetrics metrics = new WriterMetrics();
    IcebergWriterFactory factory = FakeIcebergWriter::new;
    this.writerPool = spy(new FixedIcebergWriterPool(factory, config.getWriterFlushFrequencyBytes(), config.getWriterMaximumPoolSize()));
    doReturn(Collections.singleton(record)).when(writerPool).getFlushableWriters();
    this.partitioner = mock(Partitioner.class);
    when(partitioner.partition(record)).thenReturn(record);
    this.transformer = new IcebergWriterStage.Transformer(config, metrics, this.writerPool, this.partitioner, this.scheduler, this.scheduler);
    // Catalog
    ServiceLocator serviceLocator = mock(ServiceLocator.class);
    when(serviceLocator.service(Configuration.class)).thenReturn(mock(Configuration.class));
    this.catalog = mock(Catalog.class);
    Table table = mock(Table.class);
    PartitionSpec spec = PartitionSpec.builderFor(SCHEMA).identity("id").build();
    when(table.spec()).thenReturn(spec);
    when(this.catalog.loadTable(any())).thenReturn(table);
    when(serviceLocator.service(Catalog.class)).thenReturn(this.catalog);
    when(serviceLocator.service(PartitionerFactory.class)).thenReturn(mock(PartitionerFactory.class));
    // Mantis Context
    this.context = mock(Context.class);
    when(this.context.getParameters()).thenReturn(parameters);
    when(this.context.getServiceLocator()).thenReturn(serviceLocator);
    when(this.context.getWorkerInfo()).thenReturn(new WorkerInfo("testJobName", "jobId", 1, 1, 1, MantisJobDurationType.Perpetual, "host"));
    // Flow
    Observable<Record> source = Observable.interval(1, TimeUnit.MILLISECONDS, this.scheduler).map(i -> record);
    this.flow = source.compose(this.transformer);
}
Also used : Context(io.mantisrx.runtime.Context) Parameters(io.mantisrx.runtime.parameter.Parameters) StageOverrideParameters(io.mantisrx.connector.iceberg.sink.StageOverrideParameters) Table(org.apache.iceberg.Table) Configuration(org.apache.hadoop.conf.Configuration) WorkerInfo(io.mantisrx.runtime.WorkerInfo) IcebergWriterFactory(io.mantisrx.connector.iceberg.sink.writer.factory.IcebergWriterFactory) PartitionSpec(org.apache.iceberg.PartitionSpec) Catalog(org.apache.iceberg.catalog.Catalog) WriterConfig(io.mantisrx.connector.iceberg.sink.writer.config.WriterConfig) ServiceLocator(io.mantisrx.runtime.lifecycle.ServiceLocator) FixedIcebergWriterPool(io.mantisrx.connector.iceberg.sink.writer.pool.FixedIcebergWriterPool) PartitionerFactory(io.mantisrx.connector.iceberg.sink.writer.partitioner.PartitionerFactory) GenericRecord(org.apache.iceberg.data.GenericRecord) Record(org.apache.iceberg.data.Record) TestScheduler(rx.schedulers.TestScheduler) WriterMetrics(io.mantisrx.connector.iceberg.sink.writer.metrics.WriterMetrics) Partitioner(io.mantisrx.connector.iceberg.sink.writer.partitioner.Partitioner) BeforeEach(org.junit.jupiter.api.BeforeEach)

Example 43 with Context

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

the class HttpSourceImplTest method testGettingStreamFromMultipleServers.

@Test
public void testGettingStreamFromMultipleServers() throws Exception {
    HttpSourceImpl<ByteBuf, ServerSentEvent, ServerContext<ServerSentEvent>> source = createStreamingSource();
    final AtomicInteger counter = new AtomicInteger();
    final CountDownLatch done = new CountDownLatch(1);
    final ConcurrentHashMap<String, AtomicInteger> result = new ConcurrentHashMap<>();
    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();
        }
    }).doOnError(new Action1<Throwable>() {

        @Override
        public void call(Throwable throwable) {
            fail("Unexpected failure: " + throwable);
        }
    }).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(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 (Server server : localServerProvider.getServers()) {
        assertEquals("There should be one completion per server", 1, sourceObserver.getCount(toServerInfo(server), EventType.SOURCE_COMPLETED));
        assertEquals("There should be one un-subscription per server", 1, sourceObserver.getCount(toServerInfo(server), EventType.CONNECTION_UNSUBSCRIBED));
        assertEquals("There should be no error", 0, sourceObserver.getCount(toServerInfo(server), EventType.SUBSCRIPTION_FAILED));
        assertEquals("There should be one connection per server", 1, sourceObserver.getCount(toServerInfo(server), EventType.CONNECTION_ESTABLISHED));
    }
    assertEquals(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));
    }
    assertEquals("completed source should clean up its retry servers", 0, source.getRetryServers().size());
}
Also used : Context(io.mantisrx.runtime.Context) Action0(rx.functions.Action0) Action1(rx.functions.Action1) Server(io.mantisrx.runtime.source.http.LocalServerProvider.Server) EventType(io.mantisrx.runtime.source.http.impl.HttpSourceImpl.HttpSourceEvent.EventType) ServerSentEvent(mantis.io.reactivex.netty.protocol.http.sse.ServerSentEvent) Index(io.mantisrx.runtime.source.Index) ByteBuf(io.netty.buffer.ByteBuf) CountDownLatch(java.util.concurrent.CountDownLatch) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Test(org.junit.Test)

Example 44 with Context

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

the class HttpSourceImplTest method testStreamingErrorFromServerWillNotCompleteSource.

@Test
public void testStreamingErrorFromServerWillNotCompleteSource() throws Exception {
    int eventCount = 20;
    HttpSourceImpl<ByteBuf, ServerSentEvent, ServerContext<ServerSentEvent>> source = createStreamingSource("test/finiteStream?count=" + eventCount);
    final CountDownLatch latch = new CountDownLatch(1);
    final AtomicReference<Throwable> ex = new AtomicReference<>();
    final ConcurrentHashMap<ServerInfo, Set<String>> items = new ConcurrentHashMap<>();
    Observable.merge(source.call(new Context(), new Index(1, 1))).subscribe(new Subscriber<ServerContext<ServerSentEvent>>() {

        @Override
        public void onCompleted() {
            latch.countDown();
        }

        @Override
        public void onError(Throwable e) {
            ex.set(e);
            latch.countDown();
        }

        @Override
        public void onNext(ServerContext<ServerSentEvent> pair) {
            items.putIfAbsent(pair.getServer(), new HashSet<String>());
            items.get(pair.getServer()).add(pair.getValue().contentAsString());
        }
    });
    if (latch.await(5, TimeUnit.SECONDS)) {
        fail("The test case should not finish at all");
    }
    Assert.assertNull("The timeout error should be captured by the client so it does not surface to the source", ex.get());
    for (Server server : localServerProvider.getServers()) {
        ServerInfo serverInfo = toServerInfo(server);
        assertEquals("There should be no source level error", 0, sourceObserver.getErrorCount());
        assertEquals("There should be one connection attempt per server", 1, sourceObserver.getCount(serverInfo, EventType.CONNECTION_ATTEMPTED));
        assertEquals("There should be one established connection per server ", 1, sourceObserver.getCount(serverInfo, EventType.CONNECTION_ESTABLISHED));
        assertEquals("There should no subscribed server because of read timeout", 1, sourceObserver.getCount(serverInfo, EventType.SUBSCRIPTION_ESTABLISHED));
        assertEquals(String.format("There should be %d item before simulated error per server", eventCount), eventCount, items.get(serverInfo).size());
    }
}
Also used : Context(io.mantisrx.runtime.Context) Set(java.util.Set) HashSet(java.util.HashSet) Server(io.mantisrx.runtime.source.http.LocalServerProvider.Server) ServerInfo(mantis.io.reactivex.netty.client.RxClient.ServerInfo) ServerSentEvent(mantis.io.reactivex.netty.protocol.http.sse.ServerSentEvent) AtomicReference(java.util.concurrent.atomic.AtomicReference) Index(io.mantisrx.runtime.source.Index) ByteBuf(io.netty.buffer.ByteBuf) CountDownLatch(java.util.concurrent.CountDownLatch) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashSet(java.util.HashSet) Test(org.junit.Test)

Example 45 with Context

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

the class HttpSourceImplTest method testGettingSingleEntityFromMultipleServers.

@Test
public void testGettingSingleEntityFromMultipleServers() throws Exception {
    HttpSourceImpl<ByteBuf, ByteBuf, ServerContext<ByteBuf>> source = createSingleEntitySource();
    final AtomicInteger counter = new AtomicInteger();
    final CountDownLatch done = new CountDownLatch(1);
    Observable.merge(source.call(new Context(), new Index(1, 1))).map(new Func1<ServerContext<ByteBuf>, ServerContext<String>>() {

        @Override
        public ServerContext<String> call(ServerContext<ByteBuf> pair) {
            return new ServerContext<>(pair.getServer(), pair.getValue().toString(Charset.defaultCharset()));
        }
    }).doOnNext(new Action1<ServerContext<String>>() {

        @Override
        public void call(ServerContext<String> pair) {
            counter.incrementAndGet();
            assertEquals(RequestProcessor.SINGLE_ENTITY_RESPONSE, pair.getValue());
        }
    }).doOnError(new Action1<Throwable>() {

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

        @Override
        public void call() {
            done.countDown();
        }
    }).subscribe();
    done.await(3000, TimeUnit.SECONDS);
    assertEquals(String.format("There should be exactly one response from each of the %d servers", localServerProvider.serverSize()), localServerProvider.serverSize(), counter.get());
    for (Server server : localServerProvider.getServers()) {
        ServerInfo serverInfo = toServerInfo(server);
        assertEquals("There should be one completion per server", 1, sourceObserver.getCount(serverInfo, EventType.SOURCE_COMPLETED));
        assertEquals("There should be one un-subscription per server", 1, sourceObserver.getCount(serverInfo, EventType.CONNECTION_UNSUBSCRIBED));
        assertEquals("There should be no error", 0, sourceObserver.getCount(serverInfo, EventType.SUBSCRIPTION_FAILED));
        assertEquals("There should be one connection per server", 1, sourceObserver.getCount(serverInfo, EventType.SUBSCRIPTION_ESTABLISHED));
    }
    assertEquals(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) Action0(rx.functions.Action0) Action1(rx.functions.Action1) Server(io.mantisrx.runtime.source.http.LocalServerProvider.Server) EventType(io.mantisrx.runtime.source.http.impl.HttpSourceImpl.HttpSourceEvent.EventType) ServerInfo(mantis.io.reactivex.netty.client.RxClient.ServerInfo) Index(io.mantisrx.runtime.source.Index) ByteBuf(io.netty.buffer.ByteBuf) CountDownLatch(java.util.concurrent.CountDownLatch) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) 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