MCPcopy Create free account
hub / github.com/ContentSquare/chproxy / proxyRequest

Method proxyRequest

proxy.go:285–352  ·  view source on GitHub ↗

proxyRequest proxies the given request to clickhouse and sends response to rw. srw is required only for setting non-200 status codes on timeouts or on client connection disconnects.

(s *scope, rw ResponseWriterWithCode, srw *statResponseWriter, req *http.Request)

Source from the content-addressed store, hash-verified

283// srw is required only for setting non-200 status codes on timeouts
284// or on client connection disconnects.
285func (rp *reverseProxy) proxyRequest(s *scope, rw ResponseWriterWithCode, srw *statResponseWriter, req *http.Request) {
286 // wrap body into cachedReadCloser, so we could obtain the original
287 // request on error.
288 if _, ok := req.Body.(*cachedReadCloser); !ok {
289 req.Body = &cachedReadCloser{
290 ReadCloser: req.Body,
291 }
292 }
293
294 timeout, timeoutErrMsg := s.getTimeoutWithErrMsg()
295 ctx := context.Background()
296 if timeout > 0 {
297 var cancel context.CancelFunc
298 ctx, cancel = context.WithTimeout(ctx, timeout)
299 defer cancel()
300 }
301
302 // Cancel the ctx if client closes the remote connection,
303 // so the proxied query may be killed instantly.
304 ctx, ctxCancel := listenToCloseNotify(ctx, rw)
305 defer ctxCancel()
306
307 req = req.WithContext(ctx)
308
309 startTime := time.Now()
310
311 executeDuration, err := executeWithRetry(ctx, s, s.cluster.retryNumber, rp.rp.ServeHTTP, rw, srw, req, func(duration float64) {
312 proxiedResponseDuration.With(s.labels).Observe(duration)
313 }, func(labels prometheus.Labels) { retryRequest.With(labels).Inc() })
314
315 statusCodesClickhouse.With(
316 prometheus.Labels{
317 "cluster": s.cluster.name,
318 "replica": s.host.ReplicaName(),
319 "cluster_node": s.host.Host(),
320 "code": strconv.Itoa(rw.StatusCode()),
321 },
322 ).Inc()
323 switch {
324 case err == nil:
325 return
326 case errors.Is(err, context.Canceled):
327 canceledRequest.With(s.labels).Inc()
328
329 q := getQuerySnippet(req)
330 log.Debugf("%s: remote client closed the connection in %s; query: %q", s, time.Since(startTime), q)
331 if err := s.killQuery(); err != nil {
332 log.Errorf("%s: cannot kill query: %s; query: %q", s, err, q)
333 }
334 srw.statusCode = 499 // See https://httpstatuses.com/499 .
335 case errors.Is(err, context.DeadlineExceeded):
336 timeoutRequest.With(s.labels).Inc()
337
338 // Penalize host with the timed out query, because it may be overloaded.
339 s.host.Penalize()
340
341 q := getQuerySnippet(req)
342 log.Debugf("%s: query timeout in %f; query: %q", s, executeDuration, q)

Callers 2

ServeHTTPMethod · 0.95
serveFromCacheMethod · 0.95

Calls 13

DebugfFunction · 0.92
ErrorfFunction · 0.92
listenToCloseNotifyFunction · 0.85
executeWithRetryFunction · 0.85
getQuerySnippetFunction · 0.85
respondWithFunction · 0.85
getTimeoutWithErrMsgMethod · 0.80
IncMethod · 0.80
ReplicaNameMethod · 0.80
HostMethod · 0.80
killQueryMethod · 0.80
PenalizeMethod · 0.80

Tested by

no test coverage detected