Skip to content

Commit

Permalink
Prevent ENOBUFS errors by skipping UDP send buffer size configuration (
Browse files Browse the repository at this point in the history
…#392)

The previous implementation attempted to set the UDP socket's send buffer
size, which could lead to ENOBUFS errors in some environments. This change:
- Overrides setup_socket in UDPConnection to skip buffer size configuration
- Improves socket creation by using the correct address family
- Updates error message to be more accurate ("Failed to setup socket")

This prevents potential buffer-related errors while maintaining the original
functionality for other connection types.
  • Loading branch information
pedro-stanaka authored Jan 14, 2025
1 parent 4045921 commit 6fd8c49
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 18 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ section below.

## Unreleased changes

## Version 3.9.9

- [#392](https://github.com/Shopify/statsd-instrument/pull/392) - Prevent ENOBUFS errors when using UDP, by skipping setting socket buffer size.

## Version 3.9.8

- [#390](https://github.com/Shopify/statsd-instrument/pull/391) - Fixing bug in Environment when using UDS. The max packet size option was not being passed to the
Expand Down
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,9 @@ platform :mri do
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.2")
gem "vernier", require: false
end

# From Ruby >= 3.5, logger is not part of the stdlib anymore
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.5")
gem "logger"
end
end
2 changes: 1 addition & 1 deletion lib/statsd/instrument/connection_behavior.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def setup_socket(original_socket)
original_socket
rescue IOError => e
StatsD.logger.debug do
"[#{self.class.name}] Failed to create socket: #{e.class}: #{e.message}"
"[#{self.class.name}] Failed to setup socket: #{e.class}: #{e.message}"
end
nil
end
Expand Down
9 changes: 7 additions & 2 deletions lib/statsd/instrument/udp_connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,16 @@ def type

private

def setup_socket(original_socket)
original_socket
end

def socket
@socket ||= begin
udp_socket = UDPSocket.new
family = Addrinfo.udp(host, port).afamily
udp_socket = UDPSocket.new(family)
setup_socket(udp_socket)&.tap do |s|
s.connect(@host, @port)
s.connect(host, port)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/statsd/instrument/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

module StatsD
module Instrument
VERSION = "3.9.8"
VERSION = "3.9.9"
end
end
14 changes: 0 additions & 14 deletions test/udp_sink_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,25 +151,11 @@ def test_socket_error_should_invalidate_socket
seq = sequence("connect_fail_connect_succeed")

# First attempt
socket.expects(:setsockopt)
.with(Socket::SOL_SOCKET, Socket::SO_SNDBUF, StatsD::Instrument::UdpConnection::DEFAULT_MAX_PACKET_SIZE)
.in_sequence(seq)
socket.expects(:getsockopt)
.with(Socket::SOL_SOCKET, Socket::SO_SNDBUF)
.returns(mock(int: StatsD::Instrument::UdpConnection::DEFAULT_MAX_PACKET_SIZE))
.in_sequence(seq)
socket.expects(:connect).with("localhost", 8125).in_sequence(seq)
socket.expects(:send).raises(Errno::EDESTADDRREQ).in_sequence(seq)
socket.expects(:close).in_sequence(seq)

# Second attempt after error
socket.expects(:setsockopt)
.with(Socket::SOL_SOCKET, Socket::SO_SNDBUF, StatsD::Instrument::UdpConnection::DEFAULT_MAX_PACKET_SIZE)
.in_sequence(seq)
socket.expects(:getsockopt)
.with(Socket::SOL_SOCKET, Socket::SO_SNDBUF)
.returns(mock(int: StatsD::Instrument::UdpConnection::DEFAULT_MAX_PACKET_SIZE))
.in_sequence(seq)
socket.expects(:connect).with("localhost", 8125).in_sequence(seq)
socket.expects(:send).twice.returns(1).in_sequence(seq)
socket.expects(:close).in_sequence(seq)
Expand Down

0 comments on commit 6fd8c49

Please sign in to comment.