<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Shell Grymoire</title>
  <link href="http://v2.whatthefuck.computer/grymoires/shell"/>
  <link rel="self" href="http://v2.whatthefuck.computer/grymoires/shell.xml"/>
  <updated>2025-01-16T10:59:00Z</updated>
  <author>
    <name>ryan rix &lt;garden@whatthefuck.computer&gt;</name>
  </author>
  <id>http://v2.whatthefuck.computer/grymoires/shell</id>
    <entry>
    <title>=inotify= file limits can be confusing/misleading</title>
    <link href="http://v2.whatthefuck.computer/grymoires/shell#20250116T105516.143422"/>
    <id>urn:uid:20250116T105516.143422</id>
    <published>2025-01-16T10:59:00Z</published>
    <updated>2025-01-16T10:59:00Z</updated>
    <content type="html">&lt;article&gt;&lt;h1 id=&quot;20250116T105516.143422&quot;&gt;&lt;code&gt;inotify&lt;/code&gt; file limits can be confusing/misleading&lt;/h1&gt;&lt;p&gt;I&amp;#39;ve recently been watching a build for a package on my server fail inconsistently ~50% of the times I build updates, and I was confused as to why it was missing the binary cache in the first. Oh fun, how reproduceable. I spent an hour or two yesterday reading the code and the failing tests and realized it was because the test was stress-testing &lt;code&gt;inotify&lt;/code&gt; system calls:
&lt;/p&gt;&lt;figure class=&quot;src-block&quot;&gt;&lt;figcaption class=&quot;src-block-meta&quot;&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;  Traceback (most recent call last):
    File &amp;quot;/nix/store/zv1kaq7f1q20x62kbjv6pfjygw5jmwl6-python3-3.12.7/lib/python3.12/threading.py&amp;quot;, line 1075, in _bootstrap_inner
      self.run()
    File &amp;quot;/build/source/src/documents/tests/test_management_consumer.py&amp;quot;, line 30, in run
      self.cmd.handle(directory=settings.CONSUMPTION_DIR, oneshot=False, testing=True)
    File &amp;quot;/build/source/src/documents/management/commands/document_consumer.py&amp;quot;, line 251, in handle
      self.handle_inotify(directory, recursive, options[&amp;quot;testing&amp;quot;])
    File &amp;quot;/build/source/src/documents/management/commands/document_consumer.py&amp;quot;, line 294, in handle_inotify
      inotify = INotify()
                ^^^^^^^^^
    File &amp;quot;/nix/store/3ziqbc4xcs58hhh5srx7pfl2n9mwj22g-python3.12-inotifyrecursive-0.3.5/lib/python3.12/site-packages/inotifyrecursive/inotifyrecursive.py&amp;quot;, line 31, in __init__
      inotify_simple.INotify.__init__(self)
    File &amp;quot;/nix/store/1qv923rjqijj7nbhhm9k1bz53jh9pb3a-python3.12-inotify-simple-1.3.5/lib/python3.12/site-packages/inotify_simple.py&amp;quot;, line 91, in __init__
      FileIO.__init__(self, _libc_call(_libc.inotify_init1, flags), mode=&amp;#39;rb&amp;#39;)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File &amp;quot;/nix/store/1qv923rjqijj7nbhhm9k1bz53jh9pb3a-python3.12-inotify-simple-1.3.5/lib/python3.12/site-packages/inotify_simple.py&amp;quot;, line 39, in _libc_call
      raise OSError(errno, os.strerror(errno))
  OSError: [Errno 24] Too many open files&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;&lt;a href=&quot;//man7.org/linux/man-pages/man7/inotify.7.html&quot;&gt;inotify&lt;/a&gt; is an API that allows your process to be notified when files are accessed, changed, deleted, etc. Because &lt;code&gt;inotify&lt;/code&gt; queues can use a fair bit of memory, Linux implements specific interfaces to limit these calls:
&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The following interfaces can be used to limit the amount of
kernel memory consumed by inotify:
&lt;/p&gt;&lt;p&gt;&lt;code&gt;/proc/sys/fs/inotify/max_queued_events&lt;/code&gt;
       The value in this file is used when an application calls
       inotify_init(2) to set an upper limit on the number of
       events that can be queued to the corresponding inotify
       instance.  Events in excess of this limit are dropped, but
       an IN_Q_OVERFLOW event is always generated.
&lt;/p&gt;&lt;p&gt;&lt;code&gt;/proc/sys/fs/inotify/max_user_instances&lt;/code&gt;
       This specifies an upper limit on the number of inotify
       instances that can be created per real user ID.
&lt;/p&gt;&lt;p&gt;&lt;code&gt;/proc/sys/fs/inotify/max_user_watches&lt;/code&gt;
       This specifies an upper limit on the number of watches
       that can be created per real user ID.
&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I found a &lt;a href=&quot;//github.com/NixOS/nixpkgs/issues/361006#issuecomment-2594076250&quot;&gt;Nixpkgs GitHub Issue&lt;/a&gt; about the build failure where folks saw the &amp;quot;too many open files&amp;quot; and assumed it was &lt;code&gt;ulimit&lt;/code&gt; configuration issues on the build hosts that stumped even the NixOS Super Posters, but it&amp;#39;s this &lt;strong&gt;other&lt;/strong&gt; more obscure limit that nevertheless raises the same &lt;code&gt;Errno&lt;/code&gt; when it&amp;#39;s hit. Classic Linux! These values are set to arbitrarily low values by default, and I remembered that the &lt;code&gt;inotify&lt;/code&gt; watcher in the &lt;a href=&quot;//v2.whatthefuck.computer/arcology&quot;&gt;The Arcology Project&lt;/a&gt;&amp;#39;s FastAPI prototype bumped up against these limits when I deployed it way back when. Classic Linux!
&lt;/p&gt;&lt;p&gt;There are two machines in &lt;code&gt;/etc/nix/machines&lt;/code&gt;, my &lt;a href=&quot;/404?node=20240610T102854.484036&quot; class=&quot;unpublished&quot;&gt;Framework 13 Laptop&lt;/a&gt; and &lt;a href=&quot;//v2.whatthefuck.computer/my/homeserver&quot;&gt;My Homelab Build&lt;/a&gt;. Presumably the build works on one but not the other, but I no longer explicitly set these values, so something in NixOS itself must be, this is easy enough to check:
&lt;/p&gt;&lt;figure class=&quot;src-block&quot; data-language=&quot;shell&quot; data-results=&quot;drawer&quot;&gt;&lt;figcaption class=&quot;src-block-meta&quot;&gt;&lt;span class=&quot;src-lang&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;src-arg src-results&quot;&gt;:results drawer&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pushd ~/arroyo-nix
grep -ri fs.inotify.max_user_watches
pushd ~/Code/nixpkgs
grep -ri fs.inotify.max_user_watches&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;:results:
~/arroyo-nix ~/org
~/Code/nixpkgs ~/arroyo-nix ~/org
nixos/modules/services/misc/graphical-desktop.nix:      &amp;quot;fs.inotify.max_user_watches&amp;quot; = lib.mkDefault 524288;
nixos/modules/virtualisation/lxd.nix:      &amp;quot;fs.inotify.max_user_watches&amp;quot; = 1048576;
nixos/modules/virtualisation/incus.nix:      &amp;quot;fs.inotify.max_user_watches&amp;quot; = lib.mkOverride 1050 1048576; # override in case conflict nixos/modules/services/x11/xserver.nix
:END:
&lt;/p&gt;&lt;p&gt;So it&amp;#39;s set to a higher value by enabling LXD (which I believe &lt;a href=&quot;//v2.cce.whatthefuck.computer/waydroid&quot;&gt;Waydroid&lt;/a&gt; does) but also by enabling &lt;strong&gt;any graphical desktop&lt;/strong&gt;. So the package would build on my laptop but not my server or any &amp;quot;stock&amp;quot; NixOS server... a 50-50 shot.
&lt;/p&gt;&lt;figure class=&quot;src-block&quot;&gt;&lt;figcaption class=&quot;src-block-meta&quot;&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;sudo sysctl -w fs.inotify.max_user_watches=524288
sudo sysctl -w fs.inotify.max_user_instances=524288&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;I set this temporarily on my server and the build ran reliably 5 times though the tests are sooooooo freakin&amp;#39; slow... I hope the Hydra instance that publishes the binary cache gets around to something like this, rather than disabling the tests that validate that document consumption in this  document scanning/processing service works properly....
&lt;/p&gt;&lt;p&gt;It can be set &amp;quot;for good&amp;quot; with this NixOS configuration:
&lt;/p&gt;&lt;figure class=&quot;src-block&quot; data-language=&quot;nix&quot;&gt;&lt;figcaption class=&quot;src-block-meta&quot;&gt;&lt;span class=&quot;src-lang&quot;&gt;nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code class=&quot;language-nix&quot;&gt;boot.kernel.sysctl = {
  &amp;quot;fs.inotify.max_user_instances&amp;quot; = 524288;
  &amp;quot;fs.inotify.max_user_watches&amp;quot; = 524288;
};&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/article&gt;</content>
  </entry>
    <entry>
    <title>Count 502s from each URL from web access logs</title>
    <link href="http://v2.whatthefuck.computer/grymoires/shell#20220912T114507.881904"/>
    <id>urn:uid:20220912T114507.881904</id>
    <published>2023-11-01T21:00:00Z</published>
    <updated>2023-11-01T21:00:00Z</updated>
    <content type="html">&lt;article&gt;&lt;h1 id=&quot;20220912T114507.881904&quot;&gt;Count 502s from each URL from web access logs&lt;/h1&gt;&lt;figure class=&quot;src-block&quot; data-language=&quot;shell&quot;&gt;&lt;figcaption class=&quot;src-block-meta&quot;&gt;&lt;span class=&quot;src-lang&quot;&gt;shell&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo tail -n 10000 /var/log/nginx/access.log | awk &amp;#39;$10 == &amp;quot;502&amp;quot; {print $10 &amp;quot; &amp;quot; $1 &amp;quot; &amp;quot; $8}&amp;#39; | sort | uniq -c | sort -n&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/article&gt;</content>
  </entry>
  </feed>