Make ckpool client resilient to warm-up EOFs

The stratifier can accept a connection and close it without
writing a response during early startup — the refresh loop
then logs 'ckpool poolstats failed: read len: EOF' on every
tick until the stratifier is ready, which is noisy and looks
like a real fault.

- client.Send retries once after 200ms if the server closed
  the connection before any bytes were read (io.EOF anywhere
  in the wrapped chain).
- Aggregator tracks a ckFailStreak counter: first two
  consecutive failures log at DEBUG, third and beyond escalate
  to WARN. Successful refreshes reset the streak.
This commit is contained in:
satoshi
2026-04-14 10:58:26 +03:00
parent 82941939e5
commit c92a991e89
3 changed files with 34 additions and 2 deletions
+17
View File
@@ -51,7 +51,24 @@ var ErrProtocol = errors.New("ckpool: protocol error")
// Send delivers a single command to the named ckpool socket and returns the
// raw response bytes. `sockName` is one of SocketListener, SocketStratifier,
// or SocketConnector.
//
// If the server closes the connection before writing a response (common
// during ckpool warm-up — the stratifier accepts the socket but its stats
// aren't populated yet), Send retries once after a short backoff.
func (c *Client) Send(ctx context.Context, sockName, cmd string) ([]byte, error) {
buf, err := c.sendOnce(ctx, sockName, cmd)
if err != nil && errors.Is(err, io.EOF) {
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-time.After(200 * time.Millisecond):
}
return c.sendOnce(ctx, sockName, cmd)
}
return buf, err
}
func (c *Client) sendOnce(ctx context.Context, sockName, cmd string) ([]byte, error) {
if cmd == "" {
return nil, fmt.Errorf("ckpool: empty command")
}