about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2023-09-26 21:40:00 +0000
committerEric Wong <bofh@yhbt.net>2023-12-29 17:46:58 +0000
commite2dfea8b2c74d94b66efc00c2ccab3df7af750a5 (patch)
tree3bf30114684d7d33661e1eb761b21ae11286b7d3
parentd08f1f34c0e80f36eebe2be04a8a2483be41d14a (diff)
downloadraindrops-e2dfea8b2c74d94b66efc00c2ccab3df7af750a5.tar.gz
I just debugged an issue with our system, I was witnessing the
number of file descriptor in our process grow at an alarming rate
which I mapped to our use of raindrops to report utilisation.

For various reasons we don’t call raindrops from a Rack middleware
but have one process that monitor the socket continuously, and
share that data with the workers.

Since we call tcp_listener_stats every seconds in a process
that doesn't do much else, GC very rarely triggers if at all
 which cause `InetDiagSocket` instances to accumulate very
quickly.

Each of those instances holds a file descriptor.

Looking at the raindrops implementation it seems to assume
the GC will take care of regularly closing these sockets, but
I think it’s a bit too bold of an assumption.

[ew: don't close user-passed sockets on exception]

Acked-by: Eric Wong <e@80x24.org>
-rw-r--r--ext/raindrops/linux_inet_diag.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/ext/raindrops/linux_inet_diag.c b/ext/raindrops/linux_inet_diag.c
index 2d4f503..e4050cb 100644
--- a/ext/raindrops/linux_inet_diag.c
+++ b/ext/raindrops/linux_inet_diag.c
@@ -636,7 +636,7 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
         switch (TYPE(addrs)) {
         case T_STRING:
                 rb_hash_aset(rv, addrs, tcp_stats(&args, addrs));
-                return rv;
+                goto out;
         case T_ARRAY: {
                 long i;
                 long len = RARRAY_LEN(addrs);
@@ -645,7 +645,7 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
                         VALUE cur = rb_ary_entry(addrs, 0);
 
                         rb_hash_aset(rv, cur, tcp_stats(&args, cur));
-                        return rv;
+                        goto out;
                 }
                 for (i = 0; i < len; i++) {
                         union any_addr check;
@@ -661,6 +661,7 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
                 gen_bytecode_all(&args.iov[2]);
                 break;
         default:
+                if (argc < 2) rb_io_close(sock);
                 rb_raise(rb_eArgError,
                          "addr must be an array of strings, a string, or nil");
         }
@@ -673,6 +674,7 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
         if (RHASH_SIZE(rv) > 1)
                 rb_hash_foreach(rv, drop_placeholders, Qfalse);
 
+out:
         /* let GC deal with corner cases */
         rb_str_resize(buf, 0);
         if (argc < 2) rb_io_close(sock);