Example #1
0
func (this *Controller) executeRead(context context.Context, partition *PartitionController, request *api.ReadRequest, stream api.Edgy_ReadServer) (*api.OffsetData, error) {
	reply, err := partition.HandleReadRequest(request)
	if err != nil {
		return nil, err
	}

	if len(reply.Messages) == 0 {
		// We are at the end of the stream
		return nil, io.EOF
	}

	if err := stream.Send(reply); err != nil {
		return nil, err
	}

	return reply.Offset, nil
}
Example #2
0
func (this *Controller) Read(request *api.ReadRequest, stream api.Edgy_ReadServer) error {
	if len(request.Topic) == 0 {
		return errors.New("missing topic")
	}
	if request.Offset == nil {
		return errors.New("missing offset")
	}

	this.logger.Withs(tidy.Fields{
		"topic":      request.Topic,
		"partition":  request.Partition,
		"offset":     tidy.Stringify(request.Offset),
		"continuous": request.Continuous,
	}).Debug("incoming read request")

	ref := storage.PartitionRef{
		Topic:     request.Topic,
		Partition: storage.PartitionId(request.Partition),
	}

	partition, err := this.getPartition(ref)
	if err != nil {
		this.logger.With("partition", ref.String()).WithError(err).Error("failed to get or create storage for partition")
		return err
	}

	this.logger.With("partition", ref).Debug("dispatching request")

	if !request.Continuous {
		_, err := this.executeRead(stream.Context(), partition, request, stream)
		return err
	}

	receiver := partition.Notify(stream.Context())
	errDelay := backoff.Exp(1*time.Millisecond, 5*time.Second)

	for {
		offset, err := this.executeRead(stream.Context(), partition, request, stream)
		if err != nil {
			if err != io.EOF {
				select {
				case <-errDelay.DelayC():
					continue
				case <-stream.Context().Done():
					err := stream.Context().Err()
					this.logger.WithError(err).Warn("unexpected context done signal")
					return err
				}
			}
		} else {
			request.Offset = offset
		}
		errDelay.Reset()

		select {
		case signalOffset, ok := <-receiver.channel:
			this.logger.With("signal_offset", signalOffset).With("ok", ok).Debug("receiver.channel")
			if !ok {
				this.logger.Debug("signal channel closed")
				return nil
			}
			this.logger.With("offset", signalOffset)
			continue
		case <-stream.Context().Done():
			err := stream.Context().Err()
			this.logger.WithError(err).Debug("context done")
			return err
		}
	}
}