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 }
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 } } }