<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Incident Post-Mortem on Redowan&#39;s Reflections</title>
    <link>https://rednafi.com/tags/incident-post-mortem/</link>
    <description>Recent content in Incident Post-Mortem on Redowan&#39;s Reflections</description>
    <image>
      <title>Redowan&#39;s Reflections</title>
      <url>https://blob.rednafi.com/home/cover-39e2ac8de020.png</url>
      <link>https://rednafi.com/</link>
    </image>
    <generator>Hugo -- 0.164.0</generator>
    <language>en</language>
    <dc:creator>Redowan Delowar</dc:creator>
    <lastBuildDate>Tue, 30 Jun 2026 03:47:21 +0200</lastBuildDate>
    <atom:link href="https://rednafi.com/tags/incident-post-mortem/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Dissecting an outage caused by eager-loading file content</title>
      <link>https://rednafi.com/python/outage-caused-by-eager-loading-file/</link>
      <pubDate>Fri, 14 Oct 2022 00:00:00 +0000</pubDate>
      <guid>https://rednafi.com/python/outage-caused-by-eager-loading-file/</guid>
      <dc:creator>Redowan Delowar</dc:creator>
      <description>Learn from a production outage caused by loading large CSV files into memory. Stream process files to prevent OOM errors and crashes.</description>
      <content:encoded>&lt;p&gt;Python makes it freakishly easy to load the whole content of any file into memory and
process it afterward. This is one of the first things that&amp;rsquo;s taught to people who are new to
the language. While the following snippet might be frowned upon by many, it&amp;rsquo;s definitely not
uncommon:&lt;/p&gt;
&lt;div class=&#34;codeblock&#34; translate=&#34;no&#34; data-lang=&#34;py&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# src.py&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;foo.csv&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# Load whole content of the file as a string in memory.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f_content&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# ...do your processing here.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Adopting this pattern as the default way of handling files isn&amp;rsquo;t the most terrible thing in
the world for sure. Also, this is often the preferred way of dealing with image files or
blobs. However, overzealously loading file content is only okay as long as the file size is
smaller than the volatile memory of the working system.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Moreover, you&amp;rsquo;ll need to be extra careful if you&amp;rsquo;re accepting files from users and running
further procedures on the content of those files. Indiscriminantly loading up the full
content into memory can be dangerous as it can cause OOM errors and crash the working
process if the system runs out of memory while processing a large file. This simple overlook
was the root cause of a major production incident at my workplace today.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The affected part of our primary Django monolith asks the users to upload a CSV file to a
panel, runs some procedures on the content of the file, and displays the transformed rows in
a paginated HTML table. Since the application is primarily used by authenticated users and
we knew the expected file size, there wasn&amp;rsquo;t any guardrail that&amp;rsquo;d prevent someone from
uploading a humongous file and crashing down the whole system. To make things worse, the
associated background function in the Django view was buffering the entire file into memory
before starting to process the rows. Buffering the entire file surely makes the process a
little faster but at the cost of higher memory usage.&lt;/p&gt;
&lt;p&gt;Although we were using background processes to avoid chugging files in the main server
process, that didn&amp;rsquo;t help when the users suddendly started to send large CSV files in
parallel. The workers were hitting OOM errors and getting restarted by the process manager.
In our particular case, we didn&amp;rsquo;t have much reason to buffer the whole file before
processing. Apparently, the naive way scaled up pretty gracefully and we didn&amp;rsquo;t pay much
attention since no one was uploading file that our server instances couln&amp;rsquo;t handle. We were
storing the incoming file in a &lt;code&gt;models.FileField&lt;/code&gt; type attribute of a Django model. When a
user uploads a CSV file, we&amp;rsquo;d:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open the file in binary mode via the &lt;code&gt;open(filepath, &amp;quot;rb&amp;quot;)&lt;/code&gt; callable.&lt;/li&gt;
&lt;li&gt;Buffer the whole file in memory and transform the binary content into a unicode string.&lt;/li&gt;
&lt;li&gt;Pass the stringified file-like object to &lt;code&gt;csv.DictReader&lt;/code&gt; to load that as a CSV file.&lt;/li&gt;
&lt;li&gt;Apply transformation on the rows line by line and render the HTML table.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is how the code looks:&lt;/p&gt;
&lt;div class=&#34;codeblock&#34; translate=&#34;no&#34; data-lang=&#34;py&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# src.py&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;csv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;io&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Django mandates us to open the file in binary mode.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;model_instance&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;rb&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;reader&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;csv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DictReader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;StringIO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;decode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;encoding&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;row&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;reader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# ... data processing goes here.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;csv.DictReader&lt;/code&gt; callable only accepts a file-like object that&amp;rsquo;s been opened in text
mode. However, Django&amp;rsquo;s &lt;code&gt;FileField&lt;/code&gt; type doesn&amp;rsquo;t make any assumptions about the file
content. It mandates us to open the file in binary mode and then decode it if necessary. So,
we open the file in binary mode with &lt;code&gt;model_instance.file.open(mode=&amp;quot;rb&amp;quot;)&lt;/code&gt; which returns an
&lt;code&gt;io.BufferedReader&lt;/code&gt; type file object. This file-like object can&amp;rsquo;t be passed directly to the
&lt;code&gt;csv.DictReader&lt;/code&gt; because a byte stream doesn&amp;rsquo;t have the concept of EOL and the CSV reader
need that to know where a row ends. As a consequence, the &lt;code&gt;csv.DictReader&lt;/code&gt; expects a
file-like object opened in text mode where the rows are explicitly delineated by
platform-specific EOLs like &lt;code&gt;\n&lt;/code&gt; or &lt;code&gt;\n\r&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To solve this, we load the content of the file in memory with &lt;code&gt;f.read()&lt;/code&gt; and decode it by
calling &lt;code&gt;.decode()&lt;/code&gt; on the result of the preceding operation. Then we create an in-memory
text file-like buffer by passing the decoded string to &lt;code&gt;io.StringIO&lt;/code&gt;. Now the CSV reader can
consume this transformed file-like object and build dictionaries of rows off of that.
Unfortunately, this stringified file buffer stays alive in the memory throughout the entire
lifetime of the processor function. Imagine 100s of large CSV files getting thrown at the
workers that execute the above code snippet. You see, at this point, overwhelming the
background workers doesn&amp;rsquo;t seem too difficult.&lt;/p&gt;
&lt;p&gt;When our workers started to degrade in production and the alerts went bonkers, we began
investigating the problem. After pinpointing the issue, we immediately responded to it by
vertically scaling up the machines. The surface area of this issue was quite large and we
didn&amp;rsquo;t want to hotfix it in fear of triggering inadvertent regressions. Once we were out of
the woods, we started patching the culprit.&lt;/p&gt;
&lt;p&gt;The solution to this is quite simple - convert the binary file-like object into a text
file-like object without buffering everything in memory and then pass the file to the CSV
reader. We were already processing the CSV rows in a lazy manner and just removing
&lt;code&gt;f.read()&lt;/code&gt; fixed the overzealous buffering issue. The corrected code snippet looks like
this:&lt;/p&gt;
&lt;div class=&#34;codeblock&#34; translate=&#34;no&#34; data-lang=&#34;py&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# src.py&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;csv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;io&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Django mandates us to open the file in binary mode.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;model_instance&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;rb&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;reader&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;csv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DictReader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TextIOWrapper&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;encoding&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;row&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;reader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# ... data processing goes here.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Here, &lt;code&gt;io.TextIOWrapper&lt;/code&gt; wraps the binary file-like object in a way that makes it behave as
if it were opened in text mode. In fact when you open a file in text mode, the native
implementation of &lt;code&gt;open&lt;/code&gt; returns a file-like object wrapped in &lt;code&gt;io.TextIOWrapper&lt;/code&gt;. You can
find more details about the &lt;a href=&#34;https://peps.python.org/pep-3116/#the-open-built-in-function&#34; rel=&#34;noopener noreferrer&#34; target=&#34;_blank&#34; aria-label=&#34;implementation of open (opens in new tab)&#34;&gt;implementation of open&lt;/a&gt; in &lt;a href=&#34;https://peps.python.org/pep-3116/&#34; rel=&#34;noopener noreferrer&#34; target=&#34;_blank&#34; aria-label=&#34;PEP-3116 (opens in new tab)&#34;&gt;PEP-3116&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;csv.DictReader&lt;/code&gt; callable can consume this transformed file-like object without any
further modifications. Since we aren&amp;rsquo;t calling &lt;code&gt;f.read()&lt;/code&gt; anymore, no overzealous content
buffering is going on here and we can lazily ask for new rows from the &lt;code&gt;reader&lt;/code&gt; object as we
sequentially process them.&lt;/p&gt;
&lt;h2 id=&#34;further-reading&#34;&gt;Further reading &lt;a class=&#34;anchor&#34; href=&#34;#further-reading&#34; aria-label=&#34;Permalink to Further reading&#34;&gt;&lt;span aria-hidden=&#34;true&#34;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://stackoverflow.com/questions/51152023/how-to-use-python-csv-dictreader-with-a-binary-file-for-a-babel-custom-extract&#34; rel=&#34;noopener noreferrer&#34; target=&#34;_blank&#34; aria-label=&#34;How to use python csv.DictReader with a binary file? (opens in new tab)&#34;&gt;How to use python csv.DictReader with a binary file?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- references --&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;!-- prettier-ignore-end --&gt;
</content:encoded>
      <category>Python</category>
      <category>Incident Post-mortem</category>
      <category>Django</category>
      <category>Performance</category>
    </item>
  </channel>
</rss>

