logQueryError logs a query execution failure. DuckLake-specific retryable conditions and user-attributable errors get Warn / Info so the Error level stays meaningful as an alerting signal — "Query execution errored." should mean the system genuinely went wrong (worker crash, IO failure, internal pan
(query string, err error)
| 497 | // SIGUSR1 sends one token (worker.go notifyQueryCancel); discard a token |
| 498 | // that arrived while no query was in flight — like Postgres, a cancel |
| 499 | // request targets only the query running when it is delivered, so a stale |
| 500 | // one must not kill the next query. |
| 501 | if c.server.externalCancelCh != nil { |
| 502 | select { |
| 503 | case <-c.server.externalCancelCh: |
| 504 | default: |
| 505 | } |
| 506 | go func() { |
| 507 | select { |
| 508 | case <-c.server.externalCancelCh: |
| 509 | cancel() |
| 510 | case <-ctx.Done(): |
| 511 | // Context already cancelled, nothing to do |
| 512 | } |
| 513 | }() |
| 514 | } |
| 515 | |
| 516 | var stopMonitor func() |
| 517 | if monitor { |
| 518 | stopMonitor = c.startDisconnectMonitor(ctx) |
| 519 | } |
| 520 | |
| 521 | cleanup := func() { |
| 522 | if stopMonitor != nil { |
| 523 | stopMonitor() |
| 524 | } |
| 525 | c.server.UnregisterQuery(key) |
| 526 | cancel() |
| 527 | } |
| 528 | |
| 529 | return ctx, cleanup |
| 530 | } |
| 531 | |
| 532 | // startDisconnectMonitor starts a goroutine that polls the client connection |
| 533 | // for disconnects using bufio.Reader.Peek. During query execution the message |
| 534 | // loop is blocked on the executor, so nobody else touches the bufio.Reader, |
| 535 | // making concurrent Peek calls safe. When the client sends a TCP FIN or RST, |
| 536 | // Peek returns a non-timeout error and the connection context is cancelled. |
| 537 | // |
| 538 | // The returned stop function MUST be called when query execution completes. |
| 539 | // It waits for the monitor goroutine to exit before returning, ensuring the |
| 540 | // bufio.Reader is not accessed concurrently with the message loop. |
| 541 | func (c *clientConn) startDisconnectMonitor(ctx context.Context) (stop func()) { |
| 542 | stopped := make(chan struct{}) |
| 543 | done := make(chan struct{}) |
| 544 | |
| 545 | go func() { |
| 546 | defer close(stopped) |
| 547 | for { |
| 548 | _ = c.conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) |
| 549 | _, err := c.reader.Peek(1) |
| 550 | if err != nil { |
| 551 | if netErr, ok := err.(net.Error); ok && netErr.Timeout() { |
| 552 | select { |
| 553 | case <-done: |
| 554 | return |
| 555 | case <-ctx.Done(): |
| 556 | return |