<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Twinhull</title>
    <description>The latest articles on DEV Community by Twinhull (@twinhull).</description>
    <link>https://dev.to/twinhull</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4147780%2Fdb67d409-cbb1-426a-a952-4a1fdfc9734a.png</url>
      <title>DEV Community: Twinhull</title>
      <link>https://dev.to/twinhull</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/twinhull"/>
    <language>en</language>
    <item>
      <title>Patroni: pg_rewind “password authentication failed” and the PGPASSWORD trap</title>
      <dc:creator>Twinhull</dc:creator>
      <pubDate>Sat, 03 Oct 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/twinhull/patroni-pgrewind-password-authentication-failed-and-the-pgpassword-trap-1nai</link>
      <guid>https://dev.to/twinhull/patroni-pgrewind-password-authentication-failed-and-the-pgpassword-trap-1nai</guid>
      <description>&lt;p&gt;Tested on: Patroni 4.1, PostgreSQL 16&lt;/p&gt;

&lt;p&gt;Your cluster passes every switchover test. Then the leader crashes for real, a replica takes over as it should, and the old leader never comes back: it sits in &lt;code&gt;start failed&lt;/code&gt;. We hit this in our own test lab. This article covers the cause, a one-line check, and the fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;patronictl list&lt;/code&gt; shows the crashed node stuck:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| pg2    | 10.0.0.12:5432 | Replica | start failed |    |     unknown |     |    unknown |     |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PostgreSQL's log on that node repeats every few seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FATAL:  requested timeline 3 is not a child of this server's history
DETAIL:  Latest checkpoint is at 0/8000028 on timeline 2, but in the history of the
         requested timeline, the server forked off from that timeline at 0/7008BA0.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That message only says the old leader wrote WAL the new leader never saw, so it can't follow the new timeline. Patroni is supposed to fix exactly this with &lt;code&gt;pg_rewind&lt;/code&gt;. The Patroni log shows why it didn't:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO: running pg_rewind from pg3
INFO: running pg_rewind from dbname=postgres user=rewind_user host=10.0.0.13 port=5432 ...
INFO: pg_rewind exit code=1
INFO:  stderr=pg_rewind: error: connection to server at "10.0.0.13", port 5432 failed:
       FATAL:  password authentication failed for user "rewind_user"
ERROR: Failed to rewind from healthy primary: pg3
INFO: starting as a secondary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The cause: PGPASSWORD beats .pgpass
&lt;/h2&gt;

&lt;p&gt;Patroni doesn't pass passwords on the command line. It writes them to a &lt;code&gt;.pgpass&lt;/code&gt; file (the &lt;code&gt;postgresql.pgpass&lt;/code&gt; setting) and points &lt;code&gt;pg_rewind&lt;/code&gt; and &lt;code&gt;pg_basebackup&lt;/code&gt; at it. But libpq, the library under every PostgreSQL client, looks for a password in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; a password in the connection string itself,&lt;/li&gt;
&lt;li&gt; the &lt;strong&gt;&lt;code&gt;PGPASSWORD&lt;/code&gt; environment variable&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt; the password file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So if Patroni was started with &lt;code&gt;PGPASSWORD&lt;/code&gt; in its environment, typically the superuser's password left over from someone's shell, &lt;code&gt;pg_rewind&lt;/code&gt; sends &lt;em&gt;that&lt;/em&gt; password as &lt;code&gt;rewind_user&lt;/code&gt;. Authentication fails, and the rewind is skipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why your tests didn't catch it
&lt;/h2&gt;

&lt;p&gt;The variable only hurts the Patroni process that inherited it. Nodes started cleanly by systemd weeks ago keep replicating happily. The dangerous moment is &lt;strong&gt;the restart after an incident&lt;/strong&gt;: the leader crashed, someone logs in, runs a few &lt;code&gt;psql&lt;/code&gt; commands with &lt;code&gt;PGPASSWORD&lt;/code&gt; exported, and starts Patroni from that same shell, or a recovery script does it for them. That process is the one that has to run &lt;code&gt;pg_rewind&lt;/code&gt;, and it's the one carrying the wrong password.&lt;/p&gt;

&lt;p&gt;It gets worse: Patroni points replication at the same &lt;code&gt;.pgpass&lt;/code&gt; file (&lt;code&gt;primary_conninfo&lt;/code&gt; uses &lt;code&gt;passfile=…&lt;/code&gt;, not a password), so even after a manual rebuild, a node running with that environment can't stream from the leader either. Planned switchovers in a clean test environment never show any of this. In our lab, switchovers passed every time, while every crash test failed until we found the variable in the restart path.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the variable gets there
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Starting Patroni by hand&lt;/strong&gt; after an incident, from a shell where you exported &lt;code&gt;PGPASSWORD&lt;/code&gt; to run &lt;code&gt;psql&lt;/code&gt;, e.g. &lt;code&gt;nohup patroni patroni.yml &amp;amp;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrapper and deploy scripts&lt;/strong&gt; that &lt;code&gt;source&lt;/code&gt; an environment file with &lt;code&gt;set -a&lt;/code&gt;, which exports every variable in it, and then start services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;systemd units&lt;/strong&gt; with &lt;code&gt;Environment=PGPASSWORD=…&lt;/code&gt; or an &lt;code&gt;EnvironmentFile=&lt;/code&gt; shared with other tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container images&lt;/strong&gt; that set &lt;code&gt;PGPASSWORD&lt;/code&gt; for convenience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Check in 10 seconds
&lt;/h2&gt;

&lt;p&gt;Look at the environment of the running Patroni process on every node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo tr&lt;/span&gt; &lt;span class="s1"&gt;'\0'&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; &amp;lt; /proc/&lt;span class="si"&gt;$(&lt;/span&gt;pgrep &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s1"&gt;'bin/patroni'&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/environ | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'^PG|^PATRONI_'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any &lt;code&gt;PGPASSWORD&lt;/code&gt;, &lt;code&gt;PGUSER&lt;/code&gt;, &lt;code&gt;PGHOST&lt;/code&gt; or &lt;code&gt;PGSERVICE&lt;/code&gt; line is a problem. So is any unexpected &lt;code&gt;PATRONI_*&lt;/code&gt; line: Patroni reads every &lt;code&gt;PATRONI_&lt;/code&gt;-prefixed variable as configuration, and it overrides &lt;code&gt;patroni.yml&lt;/code&gt;. That's a related trap we also hit, with a &lt;code&gt;PATRONI_LOG_DIR&lt;/code&gt; from a script sending logs somewhere unexpected.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Start Patroni only through systemd, with a clean environment:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight systemd"&gt;&lt;code&gt;    &lt;span class="k"&gt;[Service]&lt;/span&gt;
    &lt;span class="nt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;postgres
    &lt;span class="nt"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;PATH=/opt/patroni/bin:/usr/local/bin:/usr/bin:/bin
    &lt;span class="nt"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;/opt/patroni/bin/patroni /etc/patroni/patroni.yml
    &lt;span class="nt"&gt;KillMode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;process
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Remove any &lt;code&gt;PGPASSWORD&lt;/code&gt; from &lt;code&gt;Environment=&lt;/code&gt; and &lt;code&gt;EnvironmentFile=&lt;/code&gt; lines, then &lt;code&gt;systemctl daemon-reload &amp;amp;&amp;amp; systemctl restart patroni&lt;/code&gt;. PostgreSQL keeps running while Patroni restarts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the stuck node, restarting Patroni is usually enough: it retries &lt;code&gt;pg_rewind&lt;/code&gt; with the right password. If the rewind can't work any more (the WAL it needs has been recycled), rebuild it: &lt;code&gt;patronictl reinit &amp;lt;cluster&amp;gt; &amp;lt;node&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Prove it's fixed
&lt;/h2&gt;

&lt;p&gt;A switchover won't prove anything here; only a crash will. In a test environment, kill the leader's Patroni and PostgreSQL with &lt;code&gt;SIGKILL&lt;/code&gt; while writing, wait for the new leader, restart the old node, and confirm it comes back as a streaming replica. That's exactly what our &lt;code&gt;failover-drill --mode crash&lt;/code&gt; automates. After the fix, our lab's crashed leaders rejoined in about 34 seconds, every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  This trap is handled in the Twinhull HA Kit
&lt;/h3&gt;

&lt;p&gt;The kit's systemd units start Patroni with a clean environment, &lt;code&gt;preflight&lt;/code&gt; warns about exported &lt;code&gt;PG*&lt;/code&gt; variables, and the config generator refuses &lt;code&gt;PATRONI_*&lt;/code&gt; names. The crash drill proves the rewind works before production needs it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twinhullhq.com/index.html" rel="noopener noreferrer"&gt;See the kit&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://twinhullhq.com/articles/patroni-pg-rewind-password-authentication-failed.html" rel="noopener noreferrer"&gt;twinhullhq.com&lt;/a&gt;. The health-check script used in these tests is free and open source: &lt;a href="https://github.com/twinhullhq/ha-check" rel="noopener noreferrer"&gt;github.com/twinhullhq/ha-check&lt;/a&gt;. If you run Patroni in production, the full kit (templates, failover drills, DR runbook, 3-node lab) is at &lt;a href="https://twinhullhq.com" rel="noopener noreferrer"&gt;twinhullhq.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>devops</category>
      <category>database</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Patroni “Failed to get list of machines… 'int' object has no attribute 'get'” with etcd on Ubuntu 24.04</title>
      <dc:creator>Twinhull</dc:creator>
      <pubDate>Thu, 01 Oct 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/twinhull/patroni-failed-to-get-list-of-machines-int-object-has-no-attribute-get-with-etcd-on-ubuntu-4ie1</link>
      <guid>https://dev.to/twinhull/patroni-failed-to-get-list-of-machines-int-object-has-no-attribute-get-with-etcd-on-ubuntu-4ie1</guid>
      <description>&lt;p&gt;Tested on: Patroni 4.1.5, etcd 3.4.30 → 3.6.15&lt;/p&gt;

&lt;p&gt;You installed etcd with &lt;code&gt;apt&lt;/code&gt;, started a healthy 3-member cluster, and pointed Patroni at it. Patroni never starts PostgreSQL. It just logs the same error every five seconds. The problem is the etcd version, not your configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: Failed to get list of machines from http://127.0.0.1:2379/v3: AttributeError("'int' object has no attribute 'get'")
ERROR: Failed to get list of machines from http://127.0.0.1:2380/v3: AttributeError("'int' object has no attribute 'get'")
INFO: waiting on etcd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meanwhile etcd itself looks perfectly healthy, which is what makes this confusing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ etcdctl endpoint health
127.0.0.1:2379 is healthy: successfully committed proposal: took = 2.1ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The cause
&lt;/h2&gt;

&lt;p&gt;Patroni's &lt;code&gt;etcd3&lt;/code&gt; backend doesn't use gRPC. It talks to etcd's &lt;strong&gt;JSON gateway&lt;/strong&gt; over plain HTTP, the &lt;code&gt;/v3/…&lt;/code&gt; endpoints. Ubuntu 24.04's &lt;code&gt;etcd-server&lt;/code&gt; package is etcd &lt;strong&gt;3.4.30&lt;/strong&gt;. On that build, the endpoint Patroni calls first to discover cluster members doesn't answer the way Patroni expects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://127.0.0.1:2379/version
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"etcdserver"&lt;/span&gt;:&lt;span class="s2"&gt;"3.4.30"&lt;/span&gt;,&lt;span class="s2"&gt;"etcdcluster"&lt;/span&gt;:&lt;span class="s2"&gt;"3.4.0"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:2379/v3/cluster/member/list &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{}'&lt;/span&gt;
404 page not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Patroni gets back something that isn't the JSON object it expects, fails while parsing it, and retries forever. The error names a Python type, not etcd, which sends people looking in the wrong place.&lt;/p&gt;

&lt;p&gt;The same request against etcd 3.6 returns the member list, and Patroni bootstraps immediately. We confirmed both on the same machine while testing the Twinhull kit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Confirm it on your system
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;etcd &lt;span class="nt"&gt;--version&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt;                 &lt;span class="c"&gt;# 3.4.x → this is your problem&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://&amp;lt;etcd-ip&amp;gt;:2379/v3/cluster/member/list &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{}'&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the second command prints &lt;code&gt;404 page not found&lt;/code&gt; instead of JSON with a &lt;code&gt;members&lt;/code&gt; array, upgrade etcd.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: install etcd 3.5 or newer from the official release
&lt;/h2&gt;

&lt;p&gt;Distribution packages lag behind. Install the upstream release binaries, which are statically linked and have no dependencies (current as of September 2026: 3.6.15; check &lt;a href="https://github.com/etcd-io/etcd/releases" rel="noopener noreferrer"&gt;github.com/etcd-io/etcd/releases&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl disable &lt;span class="nt"&gt;--now&lt;/span&gt; etcd                    &lt;span class="c"&gt;# stop the distro etcd&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt remove &lt;span class="nt"&gt;-y&lt;/span&gt; etcd-server etcd-client

&lt;span class="nv"&gt;ETCD_VER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v3.6.15
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /tmp/etcd.tgz &lt;span class="se"&gt;\&lt;/span&gt;
  https://github.com/etcd-io/etcd/releases/download/&lt;span class="nv"&gt;$ETCD_VER&lt;/span&gt;/etcd-&lt;span class="nv"&gt;$ETCD_VER&lt;/span&gt;&lt;span class="nt"&gt;-linux-amd64&lt;/span&gt;.tar.gz
&lt;span class="nb"&gt;tar &lt;/span&gt;xzf /tmp/etcd.tgz &lt;span class="nt"&gt;-C&lt;/span&gt; /tmp
&lt;span class="nb"&gt;sudo install&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 755 /tmp/etcd-&lt;span class="nv"&gt;$ETCD_VER&lt;/span&gt;&lt;span class="nt"&gt;-linux-amd64&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;etcd,etcdctl,etcdutl&lt;span class="o"&gt;}&lt;/span&gt; /usr/local/bin/
etcd &lt;span class="nt"&gt;--version&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt;                             &lt;span class="c"&gt;# etcd Version: 3.6.15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run etcd from &lt;code&gt;/usr/local/bin/etcd&lt;/code&gt; with your own systemd unit and a config file (&lt;code&gt;--config-file /etc/etcd/etcd.conf.yml&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Upgrading an existing 3.4 cluster?&lt;/strong&gt; etcd supports upgrading one minor version at a time: 3.4 → 3.5 → 3.6, member by member. For a new Patroni cluster that has never stored anything, it's simpler to stop all members, wipe their data directories, and start fresh on 3.6.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two more things while you're here
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't switch Patroni to the old &lt;code&gt;etcd&lt;/code&gt; (v2) backend&lt;/strong&gt; to work around this. The v2 API is deprecated, and etcd 3.6 no longer serves it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;etcdctl&lt;/code&gt; without a proxy.&lt;/strong&gt; If your servers export &lt;code&gt;HTTPS_PROXY&lt;/code&gt;, add the etcd addresses to &lt;code&gt;NO_PROXY&lt;/code&gt;, or health checks may go through the proxy and time out.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Caught automatically in the Twinhull HA Kit
&lt;/h3&gt;

&lt;p&gt;The kit's &lt;code&gt;preflight&lt;/code&gt; check fails on etcd versions older than 3.5 before you install anything, and the guide installs the official 3.6 release with a hardened systemd unit and optional mutual TLS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twinhullhq.com/index.html" rel="noopener noreferrer"&gt;See the kit&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://twinhullhq.com/articles/patroni-etcd-attributeerror-int-object-has-no-attribute-get.html" rel="noopener noreferrer"&gt;twinhullhq.com&lt;/a&gt;. The health-check script used in these tests is free and open source: &lt;a href="https://github.com/twinhullhq/ha-check" rel="noopener noreferrer"&gt;github.com/twinhullhq/ha-check&lt;/a&gt;. If you run Patroni in production, the full kit (templates, failover drills, DR runbook, 3-node lab) is at &lt;a href="https://twinhullhq.com" rel="noopener noreferrer"&gt;twinhullhq.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>ubuntu</category>
      <category>devops</category>
      <category>database</category>
    </item>
  </channel>
</rss>
