func (r *QueryResponse) Close() {
	r.closeLock.Lock()
	defer r.closeLock.Unlock()
	if r.closed {
		return
	}
	r.closed = true
	if r.ackCh != nil {
		close(r.ackCh)
	}
	if r.respCh != nil {
		close(r.respCh)
	}
}
Close is used to close the query, which will close the underlying
channels and prevent further deliveries
package serf
import (
	"math"
	"regexp"
	"sync"
	"time"
)
type QueryParam struct {
	FilterNodes []string
	FilterTags map[string]string
	RequestAck bool
	Timeout time.Duration
}
func (s *Serf) DefaultQueryTimeout() time.Duration {
	n := s.memberlist.NumMembers()
	timeout := s.config.MemberlistConfig.GossipInterval
	timeout *= time.Duration(s.config.QueryTimeoutMult)
	timeout *= time.Duration(math.Ceil(math.Log10(float64(n + 1))))
	return timeout
}
func (s *Serf) DefaultQueryParams() *QueryParam {
	return &QueryParam{
		FilterNodes: nil,
		FilterTags:  nil,
		RequestAck:  false,
		Timeout:     s.DefaultQueryTimeout(),
	}
}
func (q *QueryParam) encodeFilters() ([][]byte, error) {
	var filters [][]byte
	if len(q.FilterNodes) > 0 {
		if buf, err := encodeFilter(filterNodeType, q.FilterNodes); err != nil {
			return nil, err
		} else {
			filters = append(filters, buf)
		}
	}
	for tag, expr := range q.FilterTags {
		filt := filterTag{tag, expr}
		if buf, err := encodeFilter(filterTagType, &filt); err != nil {
			return nil, err
		} else {
			filters = append(filters, buf)
		}
	}
	return filters, nil
}
type QueryResponse struct {
	ackCh chan string
	deadline time.Time
	id uint32
	lTime LamportTime
	respCh chan NodeResponse
	closed    bool
	closeLock sync.Mutex
}
func newQueryResponse(n int, q *messageQuery) *QueryResponse {
	resp := &QueryResponse{
		deadline: time.Now().Add(q.Timeout),
		id:       q.ID,
		lTime:    q.LTime,
		respCh:   make(chan NodeResponse, n),
	}
	if q.Ack() {
		resp.ackCh = make(chan string, n)
	}
	return resp
}