Search in sources :

Example 1 with EventConsumer

use of org.zalando.nakadi.repository.EventConsumer in project nakadi by zalando.

the class StreamingState method reconfigureKafkaConsumer.

private void reconfigureKafkaConsumer(final boolean forceSeek) {
    if (eventConsumer == null) {
        throw new IllegalStateException("kafkaConsumer should not be null when calling reconfigureKafkaConsumer method");
    }
    final Set<EventTypePartition> newAssignment = offsets.keySet().stream().filter(o -> !this.releasingPartitions.containsKey(o)).collect(Collectors.toSet());
    if (forceSeek) {
        // removing all the current assignments for real consumer.
        try {
            eventConsumer.reassign(Collections.emptyList());
        } catch (final NakadiException | InvalidCursorException ex) {
            throw new NakadiRuntimeException(ex);
        }
    }
    final Set<EventTypePartition> currentAssignment = eventConsumer.getAssignment();
    getLog().info("Changing kafka assignment from {} to {}", Arrays.deepToString(currentAssignment.toArray()), Arrays.deepToString(newAssignment.toArray()));
    if (!currentAssignment.equals(newAssignment)) {
        try {
            final Map<EventTypePartition, NakadiCursor> beforeFirst = getBeforeFirstCursors(newAssignment);
            final List<NakadiCursor> cursors = newAssignment.stream().map(pk -> {
                final NakadiCursor beforeFirstAvailable = beforeFirst.get(pk);
                // Checks that current cursor is still available in storage
                offsets.get(pk).ensureDataAvailable(beforeFirstAvailable);
                return offsets.get(pk).getSentOffset();
            }).collect(Collectors.toList());
            eventConsumer.reassign(cursors);
        } catch (NakadiException | InvalidCursorException ex) {
            throw new NakadiRuntimeException(ex);
        }
    }
}
Also used : ConsumedEvent(org.zalando.nakadi.domain.ConsumedEvent) Arrays(java.util.Arrays) EventTypePartition(org.zalando.nakadi.domain.EventTypePartition) IdleStreamWatcher(org.zalando.nakadi.service.subscription.IdleStreamWatcher) NakadiCursor(org.zalando.nakadi.domain.NakadiCursor) LoggerFactory(org.slf4j.LoggerFactory) Collectors.groupingBy(java.util.stream.Collectors.groupingBy) HashMap(java.util.HashMap) NakadiException(org.zalando.nakadi.exceptions.NakadiException) ZkSubscriptionClient(org.zalando.nakadi.service.subscription.zk.ZkSubscriptionClient) Partition(org.zalando.nakadi.service.subscription.model.Partition) HashSet(java.util.HashSet) Meter(com.codahale.metrics.Meter) OptionalLong(java.util.OptionalLong) JSONObject(org.json.JSONObject) SubscriptionCursorWithoutToken(org.zalando.nakadi.view.SubscriptionCursorWithoutToken) ServiceUnavailableException(org.zalando.nakadi.exceptions.ServiceUnavailableException) Map(java.util.Map) NakadiKpiPublisher(org.zalando.nakadi.service.NakadiKpiPublisher) ZkSubscription(org.zalando.nakadi.service.subscription.zk.ZkSubscription) PartitionStatistics(org.zalando.nakadi.domain.PartitionStatistics) StreamKpiData(org.zalando.nakadi.metrics.StreamKpiData) Set(java.util.Set) IOException(java.io.IOException) InvalidCursorException(org.zalando.nakadi.exceptions.InvalidCursorException) Collectors(java.util.stream.Collectors) TimeUnit(java.util.concurrent.TimeUnit) NakadiRuntimeException(org.zalando.nakadi.exceptions.NakadiRuntimeException) EventConsumer(org.zalando.nakadi.repository.EventConsumer) List(java.util.List) Stream(java.util.stream.Stream) Timeline(org.zalando.nakadi.domain.Timeline) Closeable(java.io.Closeable) Optional(java.util.Optional) Preconditions(com.google.common.base.Preconditions) SubscriptionCursor(org.zalando.nakadi.view.SubscriptionCursor) MetricUtils(org.zalando.nakadi.metrics.MetricUtils) Comparator(java.util.Comparator) Collections(java.util.Collections) Client(org.zalando.nakadi.security.Client) NakadiRuntimeException(org.zalando.nakadi.exceptions.NakadiRuntimeException) NakadiCursor(org.zalando.nakadi.domain.NakadiCursor) InvalidCursorException(org.zalando.nakadi.exceptions.InvalidCursorException) EventTypePartition(org.zalando.nakadi.domain.EventTypePartition) NakadiException(org.zalando.nakadi.exceptions.NakadiException)

Example 2 with EventConsumer

use of org.zalando.nakadi.repository.EventConsumer in project nakadi by zalando.

the class EventStreamController method streamEvents.

@RequestMapping(value = "/event-types/{name}/events", method = RequestMethod.GET)
public StreamingResponseBody streamEvents(@PathVariable("name") final String eventTypeName, @Nullable @RequestParam(value = "batch_limit", required = false) final Integer batchLimit, @Nullable @RequestParam(value = "stream_limit", required = false) final Integer streamLimit, @Nullable @RequestParam(value = "batch_flush_timeout", required = false) final Integer batchTimeout, @Nullable @RequestParam(value = "stream_timeout", required = false) final Integer streamTimeout, @Nullable @RequestParam(value = "stream_keep_alive_limit", required = false) final Integer streamKeepAliveLimit, @Nullable @RequestHeader(name = "X-nakadi-cursors", required = false) final String cursorsStr, final HttpServletRequest request, final HttpServletResponse response, final Client client) {
    final String flowId = FlowIdUtils.peek();
    return outputStream -> {
        FlowIdUtils.push(flowId);
        if (blacklistService.isConsumptionBlocked(eventTypeName, client.getClientId())) {
            writeProblemResponse(response, outputStream, Problem.valueOf(Response.Status.FORBIDDEN, "Application or event type is blocked"));
            return;
        }
        final AtomicBoolean connectionReady = closedConnectionsCrutch.listenForConnectionClose(request);
        Counter consumerCounter = null;
        EventStream eventStream = null;
        List<ConnectionSlot> connectionSlots = ImmutableList.of();
        final AtomicBoolean needCheckAuthorization = new AtomicBoolean(false);
        LOG.info("[X-NAKADI-CURSORS] \"{}\" {}", eventTypeName, Optional.ofNullable(cursorsStr).orElse("-"));
        try (Closeable ignore = eventTypeChangeListener.registerListener(et -> needCheckAuthorization.set(true), Collections.singletonList(eventTypeName))) {
            final EventType eventType = eventTypeRepository.findByName(eventTypeName);
            authorizeStreamRead(eventTypeName);
            // validate parameters
            final EventStreamConfig streamConfig = EventStreamConfig.builder().withBatchLimit(batchLimit).withStreamLimit(streamLimit).withBatchTimeout(batchTimeout).withStreamTimeout(streamTimeout).withStreamKeepAliveLimit(streamKeepAliveLimit).withEtName(eventTypeName).withConsumingClient(client).withCursors(getStreamingStart(eventType, cursorsStr)).withMaxMemoryUsageBytes(maxMemoryUsageBytes).build();
            // acquire connection slots to limit the number of simultaneous connections from one client
            if (featureToggleService.isFeatureEnabled(LIMIT_CONSUMERS_NUMBER)) {
                final List<String> partitions = streamConfig.getCursors().stream().map(NakadiCursor::getPartition).collect(Collectors.toList());
                connectionSlots = consumerLimitingService.acquireConnectionSlots(client.getClientId(), eventTypeName, partitions);
            }
            consumerCounter = metricRegistry.counter(metricNameFor(eventTypeName, CONSUMERS_COUNT_METRIC_NAME));
            consumerCounter.inc();
            final String kafkaQuotaClientId = getKafkaQuotaClientId(eventTypeName, client);
            response.setStatus(HttpStatus.OK.value());
            response.setHeader("Warning", "299 - nakadi - the Low-level API is deprecated and will " + "be removed from a future release. Please consider migrating to the Subscriptions API.");
            response.setContentType("application/x-json-stream");
            final EventConsumer eventConsumer = timelineService.createEventConsumer(kafkaQuotaClientId, streamConfig.getCursors());
            final String bytesFlushedMetricName = MetricUtils.metricNameForLoLAStream(client.getClientId(), eventTypeName);
            final Meter bytesFlushedMeter = this.streamMetrics.meter(bytesFlushedMetricName);
            eventStream = eventStreamFactory.createEventStream(outputStream, eventConsumer, streamConfig, bytesFlushedMeter);
            // Flush status code to client
            outputStream.flush();
            eventStream.streamEvents(connectionReady, () -> {
                if (needCheckAuthorization.getAndSet(false)) {
                    authorizeStreamRead(eventTypeName);
                }
            });
        } catch (final UnparseableCursorException e) {
            LOG.debug("Incorrect syntax of X-nakadi-cursors header: {}. Respond with BAD_REQUEST.", e.getCursors(), e);
            writeProblemResponse(response, outputStream, BAD_REQUEST, e.getMessage());
        } catch (final NoSuchEventTypeException e) {
            writeProblemResponse(response, outputStream, NOT_FOUND, "topic not found");
        } catch (final NoConnectionSlotsException e) {
            LOG.debug("Connection creation failed due to exceeding max connection count");
            writeProblemResponse(response, outputStream, e.asProblem());
        } catch (final NakadiException e) {
            LOG.error("Error while trying to stream events.", e);
            writeProblemResponse(response, outputStream, e.asProblem());
        } catch (final InvalidCursorException e) {
            writeProblemResponse(response, outputStream, PRECONDITION_FAILED, e.getMessage());
        } catch (final AccessDeniedException e) {
            writeProblemResponse(response, outputStream, FORBIDDEN, e.explain());
        } catch (final Exception e) {
            LOG.error("Error while trying to stream events. Respond with INTERNAL_SERVER_ERROR.", e);
            writeProblemResponse(response, outputStream, INTERNAL_SERVER_ERROR, e.getMessage());
        } finally {
            connectionReady.set(false);
            consumerLimitingService.releaseConnectionSlots(connectionSlots);
            if (consumerCounter != null) {
                consumerCounter.dec();
            }
            if (eventStream != null) {
                eventStream.close();
            }
            try {
                outputStream.flush();
            } finally {
                outputStream.close();
            }
        }
    };
}
Also used : PathVariable(org.springframework.web.bind.annotation.PathVariable) RequestParam(org.springframework.web.bind.annotation.RequestParam) FlowIdUtils(org.zalando.nakadi.util.FlowIdUtils) LoggerFactory(org.slf4j.LoggerFactory) Autowired(org.springframework.beans.factory.annotation.Autowired) NakadiException(org.zalando.nakadi.exceptions.NakadiException) NoSuchEventTypeException(org.zalando.nakadi.exceptions.NoSuchEventTypeException) ServiceUnavailableException(org.zalando.nakadi.exceptions.ServiceUnavailableException) Problem(org.zalando.problem.Problem) Map(java.util.Map) Counter(com.codahale.metrics.Counter) TimelineService(org.zalando.nakadi.service.timeline.TimelineService) TypeReference(com.fasterxml.jackson.core.type.TypeReference) FeatureToggleService(org.zalando.nakadi.service.FeatureToggleService) EventTypeChangeListener(org.zalando.nakadi.service.EventTypeChangeListener) BAD_REQUEST(javax.ws.rs.core.Response.Status.BAD_REQUEST) ConsumerLimitingService(org.zalando.nakadi.service.ConsumerLimitingService) TopicRepository(org.zalando.nakadi.repository.TopicRepository) ConnectionSlot(org.zalando.nakadi.service.ConnectionSlot) NOT_FOUND(javax.ws.rs.core.Response.Status.NOT_FOUND) PartitionStatistics(org.zalando.nakadi.domain.PartitionStatistics) RequestMethod(org.springframework.web.bind.annotation.RequestMethod) StreamingResponseBody(org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody) InvalidCursorException(org.zalando.nakadi.exceptions.InvalidCursorException) BlacklistService(org.zalando.nakadi.service.BlacklistService) RestController(org.springframework.web.bind.annotation.RestController) Collectors(java.util.stream.Collectors) List(java.util.List) Response(javax.ws.rs.core.Response) Timeline(org.zalando.nakadi.domain.Timeline) ServiceTemporarilyUnavailableException(org.zalando.nakadi.exceptions.runtime.ServiceTemporarilyUnavailableException) Optional(java.util.Optional) RequestHeader(org.springframework.web.bind.annotation.RequestHeader) UnparseableCursorException(org.zalando.nakadi.exceptions.UnparseableCursorException) Client(org.zalando.nakadi.security.Client) Storage(org.zalando.nakadi.domain.Storage) ClosedConnectionsCrutch(org.zalando.nakadi.service.ClosedConnectionsCrutch) NakadiCursor(org.zalando.nakadi.domain.NakadiCursor) RequestMapping(org.springframework.web.bind.annotation.RequestMapping) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Cursor(org.zalando.nakadi.view.Cursor) ArrayList(java.util.ArrayList) Value(org.springframework.beans.factory.annotation.Value) Meter(com.codahale.metrics.Meter) HttpServletRequest(javax.servlet.http.HttpServletRequest) ImmutableList(com.google.common.collect.ImmutableList) EventStreamFactory(org.zalando.nakadi.service.EventStreamFactory) Qualifier(org.springframework.beans.factory.annotation.Qualifier) PRECONDITION_FAILED(javax.ws.rs.core.Response.Status.PRECONDITION_FAILED) Nullable(javax.annotation.Nullable) OutputStream(java.io.OutputStream) AccessDeniedException(org.zalando.nakadi.exceptions.runtime.AccessDeniedException) EventType(org.zalando.nakadi.domain.EventType) MetricRegistry(com.codahale.metrics.MetricRegistry) Logger(org.slf4j.Logger) INTERNAL_SERVER_ERROR(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) HttpServletResponse(javax.servlet.http.HttpServletResponse) MetricUtils.metricNameFor(org.zalando.nakadi.metrics.MetricUtils.metricNameFor) IOException(java.io.IOException) FORBIDDEN(javax.ws.rs.core.Response.Status.FORBIDDEN) EventStream(org.zalando.nakadi.service.EventStream) AuthorizationValidator(org.zalando.nakadi.service.AuthorizationValidator) HttpStatus(org.springframework.http.HttpStatus) EventConsumer(org.zalando.nakadi.repository.EventConsumer) EventTypeRepository(org.zalando.nakadi.repository.EventTypeRepository) Closeable(java.io.Closeable) NoConnectionSlotsException(org.zalando.nakadi.exceptions.NoConnectionSlotsException) LIMIT_CONSUMERS_NUMBER(org.zalando.nakadi.service.FeatureToggleService.Feature.LIMIT_CONSUMERS_NUMBER) CursorError(org.zalando.nakadi.domain.CursorError) VisibleForTesting(com.google.common.annotations.VisibleForTesting) MetricUtils(org.zalando.nakadi.metrics.MetricUtils) EventStreamConfig(org.zalando.nakadi.service.EventStreamConfig) InternalNakadiException(org.zalando.nakadi.exceptions.InternalNakadiException) Collections(java.util.Collections) CursorConverter(org.zalando.nakadi.service.CursorConverter) AccessDeniedException(org.zalando.nakadi.exceptions.runtime.AccessDeniedException) NakadiCursor(org.zalando.nakadi.domain.NakadiCursor) EventType(org.zalando.nakadi.domain.EventType) Meter(com.codahale.metrics.Meter) Closeable(java.io.Closeable) InvalidCursorException(org.zalando.nakadi.exceptions.InvalidCursorException) UnparseableCursorException(org.zalando.nakadi.exceptions.UnparseableCursorException) NakadiException(org.zalando.nakadi.exceptions.NakadiException) NoSuchEventTypeException(org.zalando.nakadi.exceptions.NoSuchEventTypeException) ServiceUnavailableException(org.zalando.nakadi.exceptions.ServiceUnavailableException) InvalidCursorException(org.zalando.nakadi.exceptions.InvalidCursorException) ServiceTemporarilyUnavailableException(org.zalando.nakadi.exceptions.runtime.ServiceTemporarilyUnavailableException) UnparseableCursorException(org.zalando.nakadi.exceptions.UnparseableCursorException) AccessDeniedException(org.zalando.nakadi.exceptions.runtime.AccessDeniedException) IOException(java.io.IOException) NoConnectionSlotsException(org.zalando.nakadi.exceptions.NoConnectionSlotsException) InternalNakadiException(org.zalando.nakadi.exceptions.InternalNakadiException) NakadiException(org.zalando.nakadi.exceptions.NakadiException) InternalNakadiException(org.zalando.nakadi.exceptions.InternalNakadiException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) EventStreamConfig(org.zalando.nakadi.service.EventStreamConfig) EventConsumer(org.zalando.nakadi.repository.EventConsumer) Counter(com.codahale.metrics.Counter) EventStream(org.zalando.nakadi.service.EventStream) List(java.util.List) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) NoConnectionSlotsException(org.zalando.nakadi.exceptions.NoConnectionSlotsException) NoSuchEventTypeException(org.zalando.nakadi.exceptions.NoSuchEventTypeException) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Example 3 with EventConsumer

use of org.zalando.nakadi.repository.EventConsumer in project nakadi by zalando.

the class EventStreamControllerTest method whenNormalCaseThenParametersArePassedToConfigAndStreamStarted.

@Test
public void whenNormalCaseThenParametersArePassedToConfigAndStreamStarted() throws Exception {
    final EventConsumer eventConsumerMock = mock(EventConsumer.class);
    when(eventTypeRepository.findByName(TEST_EVENT_TYPE_NAME)).thenReturn(EVENT_TYPE);
    when(timelineService.createEventConsumer(eq(KAFKA_CLIENT_ID), eq(ImmutableList.of(NakadiCursor.of(timeline, "0", "000000000000000000"))))).thenReturn(eventConsumerMock);
    when(timelineService.getActiveTimeline(eq(EVENT_TYPE))).thenReturn(timeline);
    final ArgumentCaptor<Integer> statusCaptor = getStatusCaptor();
    final ArgumentCaptor<String> contentTypeCaptor = getContentTypeCaptor();
    final ArgumentCaptor<EventStreamConfig> configCaptor = ArgumentCaptor.forClass(EventStreamConfig.class);
    final EventStream eventStreamMock = mock(EventStream.class);
    when(eventStreamFactoryMock.createEventStream(any(), any(), configCaptor.capture(), any())).thenReturn(eventStreamMock);
    final StreamingResponseBody responseBody = createStreamingResponseBody(1, 2, 3, 4, 5, "[{\"partition\":\"0\",\"offset\":\"000000000000000000\"}]");
    final OutputStream outputStream = mock(OutputStream.class);
    responseBody.writeTo(outputStream);
    final EventStreamConfig streamConfig = configCaptor.getValue();
    assertThat(streamConfig, equalTo(EventStreamConfig.builder().withCursors(ImmutableList.of(NakadiCursor.of(timeline, "0", "000000000000000000"))).withBatchLimit(1).withStreamLimit(2).withBatchTimeout(3).withStreamTimeout(4).withStreamKeepAliveLimit(5).build()));
    assertThat(statusCaptor.getValue(), equalTo(HttpStatus.OK.value()));
    assertThat(contentTypeCaptor.getValue(), equalTo("application/x-json-stream"));
    verify(timelineService, times(1)).createEventConsumer(eq(KAFKA_CLIENT_ID), eq(ImmutableList.of(NakadiCursor.of(timeline, "0", "000000000000000000"))));
    verify(eventStreamFactoryMock, times(1)).createEventStream(eq(outputStream), eq(eventConsumerMock), eq(streamConfig), any());
    verify(eventStreamMock, times(1)).streamEvents(any(), any());
    verify(outputStream, times(2)).flush();
    verify(outputStream, times(1)).close();
}
Also used : EventConsumer(org.zalando.nakadi.repository.EventConsumer) EventStreamConfig(org.zalando.nakadi.service.EventStreamConfig) StreamingResponseBody(org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody) EventStream(org.zalando.nakadi.service.EventStream) ByteArrayOutputStream(java.io.ByteArrayOutputStream) OutputStream(java.io.OutputStream) Test(org.junit.Test)

Aggregations

EventConsumer (org.zalando.nakadi.repository.EventConsumer)3 Meter (com.codahale.metrics.Meter)2 Closeable (java.io.Closeable)2 IOException (java.io.IOException)2 OutputStream (java.io.OutputStream)2 Collections (java.util.Collections)2 List (java.util.List)2 Map (java.util.Map)2 Optional (java.util.Optional)2 Collectors (java.util.stream.Collectors)2 LoggerFactory (org.slf4j.LoggerFactory)2 NakadiCursor (org.zalando.nakadi.domain.NakadiCursor)2 PartitionStatistics (org.zalando.nakadi.domain.PartitionStatistics)2 Timeline (org.zalando.nakadi.domain.Timeline)2 InvalidCursorException (org.zalando.nakadi.exceptions.InvalidCursorException)2 NakadiException (org.zalando.nakadi.exceptions.NakadiException)2 ServiceUnavailableException (org.zalando.nakadi.exceptions.ServiceUnavailableException)2 MetricUtils (org.zalando.nakadi.metrics.MetricUtils)2 Client (org.zalando.nakadi.security.Client)2 Counter (com.codahale.metrics.Counter)1