github.com/rbisecke/kafka-go@v0.4.27/client.go (about)

     1  package kafka
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net"
     7  	"time"
     8  
     9  	"github.com/rbisecke/kafka-go/protocol"
    10  )
    11  
    12  const (
    13  	defaultCreateTopicsTimeout     = 2 * time.Second
    14  	defaultDeleteTopicsTimeout     = 2 * time.Second
    15  	defaultCreatePartitionsTimeout = 2 * time.Second
    16  	defaultProduceTimeout          = 500 * time.Millisecond
    17  	defaultMaxWait                 = 500 * time.Millisecond
    18  )
    19  
    20  // Client is a high-level API to interract with kafka brokers.
    21  //
    22  // All methods of the Client type accept a context as first argument, which may
    23  // be used to asynchronously cancel the requests.
    24  //
    25  // Clients are safe to use concurrently from multiple goroutines, as long as
    26  // their configuration is not changed after first use.
    27  type Client struct {
    28  	// Address of the kafka cluster (or specific broker) that the client will be
    29  	// sending requests to.
    30  	//
    31  	// This field is optional, the address may be provided in each request
    32  	// instead. The request address takes precedence if both were specified.
    33  	Addr net.Addr
    34  
    35  	// Time limit for requests sent by this client.
    36  	//
    37  	// If zero, no timeout is applied.
    38  	Timeout time.Duration
    39  
    40  	// A transport used to communicate with the kafka brokers.
    41  	//
    42  	// If nil, DefaultTransport is used.
    43  	Transport RoundTripper
    44  }
    45  
    46  // A ConsumerGroup and Topic as these are both strings we define a type for
    47  // clarity when passing to the Client as a function argument
    48  //
    49  // N.B TopicAndGroup is currently experimental! Therefore, it is subject to
    50  // change, including breaking changes between MINOR and PATCH releases.
    51  //
    52  // DEPRECATED: this type will be removed in version 1.0, programs should
    53  // migrate to use kafka.(*Client).OffsetFetch instead.
    54  type TopicAndGroup struct {
    55  	Topic   string
    56  	GroupId string
    57  }
    58  
    59  // ConsumerOffsets returns a map[int]int64 of partition to committed offset for
    60  // a consumer group id and topic.
    61  //
    62  // DEPRECATED: this method will be removed in version 1.0, programs should
    63  // migrate to use kafka.(*Client).OffsetFetch instead.
    64  func (c *Client) ConsumerOffsets(ctx context.Context, tg TopicAndGroup) (map[int]int64, error) {
    65  	metadata, err := c.Metadata(ctx, &MetadataRequest{
    66  		Topics: []string{tg.Topic},
    67  	})
    68  
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	topic := metadata.Topics[0]
    74  	partitions := make([]int, len(topic.Partitions))
    75  
    76  	for i := range topic.Partitions {
    77  		partitions[i] = topic.Partitions[i].ID
    78  	}
    79  
    80  	offsets, err := c.OffsetFetch(ctx, &OffsetFetchRequest{
    81  		GroupID: tg.GroupId,
    82  		Topics: map[string][]int{
    83  			tg.Topic: partitions,
    84  		},
    85  	})
    86  
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	topicOffsets := offsets.Topics[topic.Name]
    92  	partitionOffsets := make(map[int]int64, len(topicOffsets))
    93  
    94  	for _, off := range topicOffsets {
    95  		partitionOffsets[off.Partition] = off.CommittedOffset
    96  	}
    97  
    98  	return partitionOffsets, nil
    99  }
   100  
   101  func (c *Client) roundTrip(ctx context.Context, addr net.Addr, msg protocol.Message) (protocol.Message, error) {
   102  	if c.Timeout > 0 {
   103  		var cancel context.CancelFunc
   104  		ctx, cancel = context.WithTimeout(ctx, c.Timeout)
   105  		defer cancel()
   106  	}
   107  
   108  	if addr == nil {
   109  		if addr = c.Addr; addr == nil {
   110  			return nil, errors.New("no address was given for the kafka cluster in the request or on the client")
   111  		}
   112  	}
   113  
   114  	return c.transport().RoundTrip(ctx, addr, msg)
   115  }
   116  
   117  func (c *Client) transport() RoundTripper {
   118  	if c.Transport != nil {
   119  		return c.Transport
   120  	}
   121  	return DefaultTransport
   122  }
   123  
   124  func (c *Client) timeout(ctx context.Context, defaultTimeout time.Duration) time.Duration {
   125  	timeout := c.Timeout
   126  
   127  	if deadline, ok := ctx.Deadline(); ok {
   128  		if remain := time.Until(deadline); remain < timeout {
   129  			timeout = remain
   130  		}
   131  	}
   132  
   133  	if timeout > 0 {
   134  		// Half the timeout because it is communicated to kafka in multiple
   135  		// requests (e.g. Fetch, Produce, etc...), this adds buffer to account
   136  		// for network latency when waiting for the response from kafka.
   137  		return timeout / 2
   138  	}
   139  
   140  	return defaultTimeout
   141  }
   142  
   143  func (c *Client) timeoutMs(ctx context.Context, defaultTimeout time.Duration) int32 {
   144  	return milliseconds(c.timeout(ctx, defaultTimeout))
   145  }