<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Danny's blog]]></title><description><![CDATA[python, webservices, distributes systems, life hacks, learnings]]></description><link>https://blog.danwald.me</link><generator>RSS for Node</generator><lastBuildDate>Sun, 12 Apr 2026 16:10:57 GMT</lastBuildDate><atom:link href="https://blog.danwald.me/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Influence sans manipulation]]></title><description><![CDATA[Andi Roberts had a nice article on how to influence people without being manipulative.
There are 5 different types of influence methods:

Rationalization (logic)
Assertion (authority)
Negotiating (mid]]></description><link>https://blog.danwald.me/influence-sans-manipulation</link><guid isPermaLink="true">https://blog.danwald.me/influence-sans-manipulation</guid><category><![CDATA[Soft Skills]]></category><category><![CDATA[communication]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Tue, 07 Apr 2026 17:57:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60db6f287c7df7644acddc3b/5fb62ffb-1ee6-46df-b4c5-8744ef334c95.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Andi Roberts had a <a href="https://andiroberts.com/leadership-questions/how-to-influence-others-without-manipulating">nice article</a> on how to influence people without being manipulative.</p>
<p>There are 5 different types of influence methods:</p>
<ol>
<li>Rationalization (logic)</li>
<li>Assertion (authority)</li>
<li>Negotiating (middle ground)</li>
<li>Inspiring (vision)</li>
<li>Bridging (relationship)</li>
</ol>
<p>Overuse has the opposite effect. </p>
<p>Most importantly, we should humbly pick the method that resonates with the other party over our modus operandum.</p>
<p>Happy hackin'</p>
]]></content:encoded></item><item><title><![CDATA[Did I do a good job?]]></title><description><![CDATA[TL;DR:

Did I: fulfill my intention; aspire to the person I want to be; have fun.

I heard Ellen Hendriksen moonlight on one of my favorite podcasts. She talked about a question I ask myself a lot - d]]></description><link>https://blog.danwald.me/did-i-do-a-good-job</link><guid isPermaLink="true">https://blog.danwald.me/did-i-do-a-good-job</guid><category><![CDATA[self-improvement ]]></category><category><![CDATA[growth]]></category><category><![CDATA[learning]]></category><category><![CDATA[life]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Thu, 02 Apr 2026 01:37:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60db6f287c7df7644acddc3b/8f2a2af3-cc5c-4ee9-b1ea-a987faf7a7a7.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>TL;DR:</h3>
<blockquote>
<p>Did I: fulfill my intention; aspire to the person I want to be; have fun.</p>
</blockquote>
<p>I heard <a href="https://substack.com/@ellenhendriksen/p-158059681">Ellen Hendriksen</a> moonlight on one of my favorite <a href="https://www.quickanddirtytips.com/savvy-psychologist/">podcasts</a>. She talked about a question I ask myself a lot - did I do a good job?</p>
<p>As a people pleaser I crave the external acknowledgment. I need to internalize it instead. Intentional. Aspirational. Fun.</p>
<p>Do it(things) for the sake of it and having fun with everything you do. </p>
<p>Enjoy the ride where <em>It's the journey not the destination</em>.</p>
<p>Happy hackin'</p>
<h4>References</h4>
<ul>
<li><p><a href="https://www.quickanddirtytips.com/savvy-psychologist/">The Savvy Psychologishologist - podcast</a></p>
</li>
<li><p><a href="https://substack.com/@ellenhendriksen/p-158059681">How to know you did a good job - Ellen Hendriksen</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Consistent Hashing]]></title><description><![CDATA[Adding more servers (horizontal scaling) is the key to managing load. Distributing data access across a set of servers allows for high throughput.
In cloud systems it's a given that a server will go d]]></description><link>https://blog.danwald.me/consistent-hashing</link><guid isPermaLink="true">https://blog.danwald.me/consistent-hashing</guid><category><![CDATA[System Design]]></category><category><![CDATA[architecture]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[cache]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Thu, 19 Mar 2026 11:45:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60db6f287c7df7644acddc3b/6d64325b-34ae-499c-a13d-38cf52d5d08e.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Adding more servers (horizontal scaling) is the key to managing load. Distributing data access across a set of servers allows for high throughput.</p>
<p>In cloud systems it's a given that a server will go down and another will come up to take its place. Consistent hashing is a technique that minimizes the thundering herd of cache misses when the number of servers changes.</p>
<p>If you have a fixed set of servers <code>n</code> and use a naive modulo hash to route requests, about <code>(n-1) / n</code> keys get remapped on a topology change — getting worse as cluster size grows. Modulo hashing has no memory of where a key was. Every topology change is a complete re-derivation from scratch, so the old and new assignments are essentially independent. Two independent uniform distributions over different-sized sets overlap very little.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60db6f287c7df7644acddc3b/ef6fcb78-f90d-46fb-9174-c6c44053b1d1.png" alt="" style="display:block;margin:0 auto" />

<p>Consistent hashing puts each server on a ring. Each incoming request is hashed to a position and the closest clockwise server handles the request. This reduces the number of keys that need to be redistributed to <code>1 / n</code>. It trades a big coordinated miss storm for a small, localized one where only the keys of the preceding neighbor's range are affected. The load is further balanced by adding virtual nodes to the ring. Consistent hashing doesn't solve the problem of hot keys, though. That could be handled by request coalescing, more v-nodes for hot keys or local application caches.</p>
<h3>References</h3>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Thundering_herd_problem">Thundering Herd Problem</a></li>
</ul>
<hr />
<blockquote>
<p>This article is part of the <a href="https://blog.danwald.me/series/system-design">system design series</a> where I am summarizing chapters from The System Design Interview: <a href="https://www.amazon.ae/Independently-Published-System-Design-Interview/dp/B08CMF2CQF">Volume 1</a> / <a href="https://www.amazon.ae/System-Design-Interview-Insiders-Guide/dp/1736049119">Volume 2</a> amongst other related content</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Design a Rate Limiter]]></title><description><![CDATA[Clients are identified by user_id, Ip address or other modalities where server side rate limiters offer more control and not prone to manipulations over their client side variations.
RateLimiters have]]></description><link>https://blog.danwald.me/design-a-rate-limiter</link><guid isPermaLink="true">https://blog.danwald.me/design-a-rate-limiter</guid><category><![CDATA[Web Development]]></category><category><![CDATA[architecture]]></category><category><![CDATA[distributed system]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Wed, 04 Mar 2026 17:16:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/y0KDPkYwBNY/upload/602ee61c2b97f150921bfec3f47103a5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="https://mermaid.ai/live/edit#pako:eNplkE1u2zAQha9CzCoGbEM_tC0TQYEi3QSwgdbd1fSCEMeWYP04pNg0NXyGLgp0m1UOkF1ulRwhpKgIiauFQA7ne2_eHCGtJQKDbVHfpplQDVmseEXsd1XkWDUXaw4v9_8enp_-kJf7v48cNgP_vjIF6vUFh_bAYbDpOJFm6LAVylz7NpK64hlLRiPC4WB0RpSXsJVPnn8n5dtaAfmhcbVYdmqLpbMTDRZ5mTeoiK-XuZQF3grlnN-H-g_3HtqkKeo3-c9fr62q_ZPvqH6i0r2IAy79VBmme9K69lO51O1a2vhXtaka3YXqd9RbYnVj0GDHLr9Zx6UdQeyQdA_nBI3mjDR1TUpR3RGFtk335j6eI2AIO5VLYI0yOIQSVSncFY7ulUOTYWnVmT1KofYceHWyzEFUP-q6fMNUbXYZsK0otL2Zg7Q7_pKLnRJlX1VYSVRtTmAxpZNWBdgRfgEbhXQyjqMooEk4pdFsQqdDuAMWhck4DONZRJNpHM-n8-Q0hN-tczgObGkWJwEN5hENZtHpFSKozns"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771384170590/f7e720ac-5d84-4778-9a86-5de2ec6ba7a8.png" alt="" style="display:block;margin:0 auto" /></a></p>
<p>Clients are identified by user_id, Ip address or other modalities where <strong>server side</strong> rate limiters offer <strong>more control</strong> and <strong>not prone to manipulations</strong> over their client side variations.</p>
<p>RateLimiters have jurisdiction of the whole system and are usually placed in a <strong>centralized location</strong> like an <strong>API Gateway</strong>. They can filter by urls (Layer 7) or by IPs via IPTables (Layer 4).</p>
<h3>Algorithms:</h3>
<ol>
<li><p><strong>Token bucket:</strong> request per token and automatically refilled at a predetermined rate with max bucket size. Requires a bucket per limit and might be hard to tune with only two parameters(fill rate and bucket size) but memory efficient and allows burst traffic.</p>
</li>
<li><p><strong>Leaking bucket:</strong> implemented as a queue fixed length queue which drops excess requests and are processed at a fixed rate. Good for stable processing rates however burst traffic could fill up the queue and delay recent requests. There are only two parameters available for tuning (queue size and number of workers processing variable length requests)</p>
</li>
<li><p><strong>Fixed window counter:</strong> Timeline is split into fixed sized windows with a predefined threshold which if a request counter exceeds is dropped. Burst traffic at the falling/starting edge of consecutive windows could breach the max threshold</p>
</li>
<li><p><strong>Sliding window log:</strong> timestamps of requests are logged. If the log size for a time window exceeds a predetermined threshold its dropped. Capable of accuracy at the expense of excessive memory for timestamps of all (even rejected) requests.</p>
</li>
<li><p><strong>Sliding windows counter:</strong> A predefined threshold is configured. The current request count is calculated as a weighted percentage current window’s sub interval, incremented by weighted percentage of the previous window’s interval. Since this is an approximation, thresholds could be exceed for bursty traffic.</p>
</li>
</ol>
<p><strong>Rules are stored on disk</strong> as configurations that can be periodically synced or pushed on update to a centralized cache used by the rate limiter middleware. Use in a <strong>single distributed memory cache</strong> like redis to <strong>avoid synchronization issues</strong> across rate limiter applications. <strong>Batch operations</strong> <strong>with pipelining</strong> and leverage <strong>sorted data sets</strong> so increment, decrement, expire and query values to avoid race conditions.</p>
<p>User <code>X-RateLimit-[ Remaining | Limit | Retry-After ]</code> headers informing clients of their limits are or when they can try back after a <strong>HTTP 429 “Too many Requests”</strong> response.</p>
<p>Avoid being rate limited using <strong>client side cache</strong>, <strong>honor</strong> RateLimit <strong>headers</strong> and add sufficient <strong>backoff time</strong> for any retry logic.</p>
<hr />
<blockquote>
<p>This article is part of the <a href="https://blog.danwald.me/series/system-design">system design series</a> where I am summarizing chapters from The System Design Interview: <a href="https://www.amazon.ae/Independently-Published-System-Design-Interview/dp/B08CMF2CQF">Volume 1</a> / <a href="https://www.amazon.ae/System-Design-Interview-Insiders-Guide/dp/1736049119">Volume 2</a> amongst other related content</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Twenty Three lessons: Mary Kay Ash]]></title><description><![CDATA[Summary of the @shaneparrish #podcast

The golden rule of leadership (treat employees with the same respect, empathy, and consideration as you'd like)

Build with people (people are the asset)

Succum]]></description><link>https://blog.danwald.me/twenty-three-lessons-mary-kay-ash</link><guid isPermaLink="true">https://blog.danwald.me/twenty-three-lessons-mary-kay-ash</guid><category><![CDATA[sales]]></category><category><![CDATA[rules]]></category><category><![CDATA[podcast]]></category><category><![CDATA[summary]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Wed, 04 Mar 2026 17:00:19 GMT</pubDate><enclosure url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/60db6f287c7df7644acddc3b/374bbd03-a63d-41ae-8160-450f38d3cab6.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="https://fs.blog/knowledge-project-podcast/outliers-mary-kay-ash/">Summary</a> of the @shaneparrish #podcast</p>
<ol>
<li><p>The golden rule of leadership (treat employees with the same respect, empathy, and consideration as you'd like)</p>
</li>
<li><p>Build with people (people are the asset)</p>
</li>
<li><p>Succumb to the invisible sign (make others feel important)</p>
</li>
<li><p>Praise people to success (recognition)</p>
</li>
<li><p>The art of listening (do it more than talking)</p>
</li>
<li><p>Criticize the act not the person (sandwiched between two heavy layers of praise)</p>
</li>
<li><p>Be a follow-through person (do what you say)</p>
</li>
<li><p>Be enthusiastic (it's contagious; derived from Greek - 'God within')</p>
</li>
<li><p>Leaders set the pace</p>
</li>
<li><p>People support what they help create</p>
</li>
<li><p>Open-door policy</p>
</li>
<li><p>Help other people get what they want (to get what you want)</p>
</li>
<li><p>Don't compromise your principles</p>
</li>
<li><p>Instill a matter of pride into your people's work</p>
</li>
<li><p>Don't rest on your laurels</p>
</li>
<li><p>Encourage taking calculated risks (avoid discouraging, being too hard on failure)</p>
</li>
<li><p>Enjoy your work with humor</p>
</li>
<li><p>Nothing happens till somebody sells</p>
</li>
<li><p>Don't hide behind policy</p>
</li>
<li><p>Be a problem solver (distinguishing between real and imaginary)</p>
</li>
<li><p>Less stress (environment)</p>
</li>
<li><p>Develop people (promote from within)</p>
</li>
<li><p>Live by the golden rule on and off the job</p>
</li>
</ol>
<h3>References</h3>
<ul>
<li><p><a href="https://en.wikipedia.org/wiki/Mary_Kay_Ash">Mary Kay Ash</a></p>
</li>
<li><p><a href="https://fs.blog/knowledge-project-podcast/outliers-mary-kay-ash/">Outliers blog/podcast</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[The Odyssey Plan: Design Thinking for Your Career]]></title><description><![CDATA[While navigating a job change I came across the Odyssey Plan from Stanford's Life Design Lab. It's a framework from Bill Burnett and Dave Evans (the "Designing Your Life" authors) that applies design thinking to career planning. As engineers, we prot...]]></description><link>https://blog.danwald.me/the-odyssey-plan-design-thinking-for-your-career</link><guid isPermaLink="true">https://blog.danwald.me/the-odyssey-plan-design-thinking-for-your-career</guid><category><![CDATA[Career]]></category><category><![CDATA[career advice]]></category><category><![CDATA[planning]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Fri, 30 Jan 2026 15:37:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/cBY2CtqQ6YI/upload/8ae9a217fc0a77e02038aa2aa8b8b372.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While navigating a job change I came across the Odyssey Plan from Stanford's Life Design Lab. It's a framework from Bill Burnett and Dave Evans (the "Designing Your Life" authors) that applies design thinking to career planning. As engineers, we prototype systems all the time. So …</p>
<blockquote>
<p>why not prototype our lives?</p>
</blockquote>
<h2 id="heading-the-framework">The Framework</h2>
<p>The Odyssey Plan asks you to map out three radically different <strong>5-year futures</strong>:</p>
<ul>
<li><p><strong>Plan 1:</strong> Your current trajectory. What does life look like if you stay the course?</p>
</li>
<li><p><strong>Plan 2:</strong> What would you do if Plan 1 vanished tomorrow? The rug-pull scenario.</p>
</li>
<li><p><strong>Plan 3:</strong> What would you do if money and other people's opinions didn't matter?</p>
</li>
</ul>
<p>The key constraint: these need to be genuinely <strong><em>different paths</em></strong>, not variations of the same thing. Being a Staff Engineer at Company A vs Company B isn't two different lives. Same life with different logos.</p>
<h2 id="heading-why-it-works">Why It Works</h2>
<p>Engineers love prototyping. We spike solutions, run experiments, validate assumptions. The Odyssey Plan is basically prototyping applied to career decisions.</p>
<p>The three questions force you to surface things you might be avoiding:</p>
<ol>
<li><p><strong>Unfinished business:</strong> What's nagging at you? That side project you never shipped? The domain you always wanted to work in? The skill you keep meaning to learn?</p>
</li>
<li><p><strong>Contingency planning:</strong> Most of us don't think about what happens if our current situation disappears. Layoffs happen. Companies pivot. Industries shift. What's your backup?</p>
</li>
<li><p><strong>Permission to dream:</strong> Plan 3 is where it gets interesting. Removing money and social pressures reveals what you actually want versus what you think you should want.</p>
</li>
</ol>
<h2 id="heading-the-dashboard">The Dashboard</h2>
<p>For each plan, you rate yourself on four metrics:</p>
<ul>
<li><p><strong>Resources</strong>: Do you have the time, money, skills, and network to pull this off?</p>
</li>
<li><p><strong>Likability</strong>: How excited are you about this future?</p>
</li>
<li><p><strong>Confidence</strong>: Can you actually make this happen?</p>
</li>
<li><p><strong>Coherence</strong>: Does this align with your values and worldview?</p>
</li>
</ul>
<p>It's like a health check for life plans. Low confidence but high likability? Maybe you need to prototype that path with smaller experiments. High resources but low likability? You might be optimizing for the wrong thing.</p>
<h2 id="heading-applying-it">Applying It</h2>
<p>I spent an evening sketching out my three plans. The exercise bought a few things to light:</p>
<p>Plan 1 was comfortable but had some gaps I'd been ignoring. Plan 2 forced me to think about what I'd actually do if my current role evaporated. Plan 3 was the most revealing. When you strip away external validation, what's left?</p>
<p>The goal isn't to pick one plan and commit. It's to have <strong>more ideas</strong>, because more ideas means better ideas. Some elements from Plan 3 might be worth prototyping in Plan 1. Some contingencies from Plan 2 might be worth preparing for now.</p>
<p>Life design is just applying the engineering experimentation and prototyping mindset to career decisions instead of code.</p>
<p>The authors put it well: designers don't think their way forward, they build their way forward.</p>
<p>Happy hackin'!</p>
<p><strong>References</strong>:</p>
<ul>
<li><p><a target="_blank" href="http://lifedesignlab.stanford.edu/">Stanford Life Design Lab</a></p>
</li>
<li><p><a target="_blank" href="https://designingyour.life/wp-content/uploads/2025/03/Odysseys-Worksheet-1.pdf">Odyssey Planning Worksheet</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Missing initial migration]]></title><description><![CDATA[Using the Flask-Migrate extension you can create database migrations for your application.
Flask application’s typically auto-create db tables on start

So running flask db upgrade you’ll get:

INFO [alembic.env] No changes in schema detected.

To cr...]]></description><link>https://blog.danwald.me/missing-initial-migration</link><guid isPermaLink="true">https://blog.danwald.me/missing-initial-migration</guid><category><![CDATA[Flask Framework]]></category><category><![CDATA[database migrations]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Fri, 23 Jan 2026 16:56:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/h5ZqVoCDgys/upload/865d211a4a31e036cb5778acf6c95231.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Using the <a target="_blank" href="https://pypi.org/project/Flask-Migrate/">Flask-Migrate</a> extension you can create database migrations for your application.</p>
<p>Flask application’s typically auto-create db tables on start</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768907722395/103e2b9b-d0ba-4107-8cb1-158676d11cac.png" alt class="image--center mx-auto" /></p>
<p>So running <code>flask db upgrade</code> you’ll get:</p>
<blockquote>
<p><code>INFO [alembic.env] No changes in schema detected.</code></p>
</blockquote>
<p>To create the initial migration, override the applications existing database with a temporary memory-based one</p>
<blockquote>
<p><code>DATABASE_URL=sqlite:/// flask db migrate</code></p>
</blockquote>
<p>Happy hackin’!</p>
<h3 id="heading-references">References</h3>
<ul>
<li><p>Flask-Migrate: <a target="_blank" href="https://flask-migrate.readthedocs.io/">Documentation</a></p>
</li>
<li><p>Alembic: <a target="_blank" href="https://alembic.sqlalchemy.org/en/latest/cookbook.html">Cookbook - Building an Up to Date Database from Scratch</a></p>
</li>
<li><p>Miguel Grinberg: <a target="_blank" href="https://blog.miguelgrinberg.com/post/how-to-add-flask-migrate-to-an-existing-project">How To Add Flask-Migrate To An Existing Project</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Ors & Ands]]></title><description><![CDATA[I came across Stephen Grupetta’s article that highlights a nuance that I didn’t consider. or and and don't return booleans. They return one of their operands which can be any data type.
The Rules
or:

Returns the first operand when it's truthy

Retur...]]></description><link>https://blog.danwald.me/ors-and-ands</link><guid isPermaLink="true">https://blog.danwald.me/ors-and-ands</guid><category><![CDATA[Python]]></category><category><![CDATA[logic]]></category><category><![CDATA[Operators]]></category><category><![CDATA[Boolean]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Tue, 20 Jan 2026 10:53:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/GOtVDsYKGUc/upload/2f1c2e10b548939fd2e7d9c7199a5bfb.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I came across <a target="_blank" href="https://x.com/s_gruppetta">Stephen Grupetta’s</a> <a target="_blank" href="https://www.thepythoncodingstack.com/p/do-you-really-know-how-or-and-and-work-in-python">article</a> that highlights a nuance that I didn’t consider. <code>or</code> and <code>and</code> <em>don't</em> return booleans. They return one of their operands which can be any data type.</p>
<h3 id="heading-the-rules">The Rules</h3>
<p><code>or</code>:</p>
<ul>
<li><p>Returns the first operand when it's truthy</p>
</li>
<li><p>Returns the second operand when the first is falsy</p>
</li>
</ul>
<p><code>and</code>:</p>
<ul>
<li><p>Returns the first operand when it's falsy</p>
</li>
<li><p>Returns the second operand when the first is truthy</p>
</li>
</ul>
<p>Python objects are either truthy or falsy, it doesn't matter that <code>or</code> and <code>and</code> don't return Booleans! Leverage this to short circuit on assignment for idiomatic code and avoid a <a target="_blank" href="https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments">gotcha</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768269342753/0d14e3d3-6ed2-40f7-8c3f-ffb9c5af4846.png" alt class="image--center mx-auto" /></p>
<p>Happy Hackin’</p>
<h2 id="heading-references">References</h2>
<ul>
<li><p><a target="_blank" href="https://x.com/s_gruppetta"><strong>Stephen Gruppetta on X</strong></a></p>
</li>
<li><p><a target="_blank" href="https://www.thepythoncodingstack.com/p/do-you-really-know-how-or-and-and-work-in-python">The Python Coding Stack: Do You Really Know How <code>or</code> And <code>and</code> Work in Python?</a></p>
</li>
<li><p><a target="_blank" href="https://docs.python.org/3/library/stdtypes.html#truth-value-testing">Python Docs: Truth Value Testing</a></p>
</li>
<li><p><a target="_blank" href="https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not">Python Docs: Boolean Operations</a></p>
</li>
<li><p><a target="_blank" href="https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments">Python Gotchas: Mutable default Arguments</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Inaccurate celery task status]]></title><description><![CDATA[Getting the status of a celery task

task_result = AsyncResult(task_id, app=celery_app)

works correctly if you have a result backend configured and tasks are defined with @app.task(bind=True). The result would be STARTED; SUCCESS; FAILURE; RETRY; RE...]]></description><link>https://blog.danwald.me/inaccurate-celery-task-status</link><guid isPermaLink="true">https://blog.danwald.me/inaccurate-celery-task-status</guid><category><![CDATA[task-status]]></category><category><![CDATA[celery]]></category><category><![CDATA[async]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Fri, 09 Jan 2026 02:54:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/vRdrtcrAWAA/upload/8b1d4a4273ca380f7cb748d72072cfc7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Getting the <a target="_blank" href="https://docs.celeryq.dev/en/latest/userguide/tasks.html#states">status of a celery task</a></p>
<blockquote>
<p><code>task_result = AsyncResult(task_id, app=celery_app)</code></p>
</blockquote>
<p>works correctly if you have a result backend configured and tasks are defined with <code>@app.task(bind=True)</code>. The result would be <code>STARTED</code>; <code>SUCCESS</code>; <code>FAILURE</code>; <code>RETRY</code>; <code>REVOKED</code>.</p>
<p><a target="_blank" href="https://kroki.io/mermaid/svg/eNqVVE2P0zAQvfMr5sYuoovEsQekVZtF5WNB_ViEEAfXmaSmrl3s8ab990wcp0n2A4oPOThv3jy_N7YnQThVonRiN7p_-wJ4_Xj1E0ajd_A1u53Obt-PYSn8FnxY7xQR5k9jVmZrbGUiNiLiJ_2O0MXyer7MpmP4Zt0WHeyV3HoIe6C2pI-eZx-ySYTH7g5_oeTmcOFYMGjFWl4Dkrx8onI5_z6GOZI7AjlVlui4cI2FdQiehKNOYBLVCFxNJtlikTpKu9trJPRgrNsJrY-PCm6uZ59W86yVKJRnNB4k7klZ8wiehPXBLor8W8ndl489E-7tlo9SbZRGcMEYZcruLJF_mEpjgpcbzINO0XWwk_7P4hClqKQf84RtBDW-xBLOPe6l0sFeG9mDzXiCwV78GMs5cjobAlu0iuOfes2MIiV0HRfDqg2abkzqpTz8DhjqXAPVXE2wSTaaPPI_1y1ZfGKL7jLlGtlQdgBlaKnqtT6CgCpO7Vn00eEheaW0ZvrkckctCuKrIG0wlPP1eYMkzjtBk8mwSTuyHb0PUqL3RWjH91-8KdchbyF43nIQXFtZ85I6Y04HAhHI7gQpKc5tlSbjgU_CgxRGota9Y-CBXTL_wdwM4pD69IQ0L0GPvI6bbx9c4FV5Bd0Dczno9gd9FnWs"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767926044912/69f559e4-3c70-4786-88c4-26fd7f5ebab5.png" alt="celery state transition" class="image--center mx-auto" /></a></p>
<p>When staring tasks, I’d always get a <code>PENDING</code> status regardless of the queried <code>task_id</code>. The <code>PENDING</code> state is celery's default state for any task whose status is unknown or has no history.</p>
<p>The workaround: write the <code>task_id</code> to Redis (Celery's result backend) on task start, then only report status for <code>task_id</code>'s that exist there. Also enable <code>track_started=True</code> by default, long-running tasks in chains show as <code>PENDING</code> until completion, which is pointless for monitoring.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">trigger_chain</span>(<span class="hljs-params">task_chain</span>):</span>
    future = task_chain.apply_async()
    celery_app.backend.client.set(<span class="hljs-string">f"<span class="hljs-subst">{future.id}</span>"</span>, <span class="hljs-string">"started"</span>, ex=<span class="hljs-number">86400</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_task_result</span>(<span class="hljs-params">task_id: str</span>):</span>
    <span class="hljs-keyword">try</span>:
        task_result = AsyncResult(task_id, app=celery_app)
        <span class="hljs-keyword">if</span> task_result.status == <span class="hljs-string">"PENDING"</span>:
            <span class="hljs-comment"># Access the backend to check if the task key exists</span>
            backend = celery_app.backend
            task_key, backend_client = (
                backend.get_key_for_task(task_id), gettattr(backend, <span class="hljs-string">"client"</span>, <span class="hljs-literal">None</span>
            )

            <span class="hljs-comment"># Check if the key exists in Redis</span>
            <span class="hljs-keyword">if</span> backend_client <span class="hljs-keyword">and</span> 
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> ( backend_client.exists(key) <span class="hljs-keyword">or</span> backend_client.exists(task_id)):
                    <span class="hljs-comment"># Task doesn't exist in the result backend</span>
                    <span class="hljs-keyword">return</span> jsonify(
                        {
                            <span class="hljs-string">"error"</span>: <span class="hljs-string">"Task not found"</span>,
                            <span class="hljs-string">"task_id"</span>: task_id,
                            <span class="hljs-string">"message"</span>: <span class="hljs-string">"No task with this ID exists in the result backend"</span>,
                        }
                    ), <span class="hljs-number">404</span>
        <span class="hljs-comment"># Valid task</span>
        response = {
            <span class="hljs-string">"task_id"</span>: task_id,
            <span class="hljs-string">"status"</span>: task_result.status,
        }
</code></pre>
<p>Happy hackin’</p>
<h3 id="heading-references">References:</h3>
<ul>
<li><p><a target="_blank" href="https://docs.celeryq.dev/en/latest/userguide/tasks.html#states">Celery: Task States</a></p>
</li>
<li><p><a target="_blank" href="https://kroki.io/mermaid/svg/eNqVVE2P0zAQvfMr5sYuoovEsQekVZtF5WNB_ViEEAfXmaSmrl3s8ab990wcp0n2A4oPOThv3jy_N7YnQThVonRiN7p_-wJ4_Xj1E0ajd_A1u53Obt-PYSn8FnxY7xQR5k9jVmZrbGUiNiLiJ_2O0MXyer7MpmP4Zt0WHeyV3HoIe6C2pI-eZx-ySYTH7g5_oeTmcOFYMGjFWl4Dkrx8onI5_z6GOZI7AjlVlui4cI2FdQiehKNOYBLVCFxNJtlikTpKu9trJPRgrNsJrY-PCm6uZ59W86yVKJRnNB4k7klZ8wiehPXBLor8W8ndl489E-7tlo9SbZRGcMEYZcruLJF_mEpjgpcbzINO0XWwk_7P4hClqKQf84RtBDW-xBLOPe6l0sFeG9mDzXiCwV78GMs5cjobAlu0iuOfes2MIiV0HRfDqg2abkzqpTz8DhjqXAPVXE2wSTaaPPI_1y1ZfGKL7jLlGtlQdgBlaKnqtT6CgCpO7Vn00eEheaW0ZvrkckctCuKrIG0wlPP1eYMkzjtBk8mwSTuyHb0PUqL3RWjH91-8KdchbyF43nIQXFtZ85I6Y04HAhHI7gQpKc5tlSbjgU_CgxRGota9Y-CBXTL_wdwM4pD69IQ0L0GPvI6bbx9c4FV5Bd0Dczno9gd9FnWs">Task State Transitions</a></p>
</li>
<li><p><a target="_blank" href="https://docs.celeryq.dev/en/latest/userguide/configuration.html#task-track-started">Celery: track_task_started</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[anti fragile]]></title><description><![CDATA[Tal Ben-Shahar's video talking about anti fragility is definitely worth the watch. Here’s what I learned.
Type 1 resilience is elastic. Under stress you bend and can return to your previous state. A non plastic deformation of a spring. Type 2 resilie...]]></description><link>https://blog.danwald.me/anti-fragile</link><guid isPermaLink="true">https://blog.danwald.me/anti-fragile</guid><category><![CDATA[antifragile]]></category><category><![CDATA[fragile]]></category><category><![CDATA[Happiness]]></category><category><![CDATA[growth]]></category><category><![CDATA[Life lessons]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Mon, 29 Dec 2025 17:15:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/YtoNx53Vc78/upload/49b21efa444191c548b32fac54ce80aa.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://x.com/TalBenShahar">Tal Ben-Shahar's</a> <a target="_blank" href="https://youtu.be/q6yPcEk93nk?si=bH6XPjY0rClzbbBU">video</a> talking about anti fragility is definitely worth the watch. Here’s what I learned.</p>
<p>Type 1 resilience is elastic. Under stress you bend and can return to your previous state. A non plastic deformation of a spring. Type 2 resilience is growth under pressure where you become stronger. It’s weight training at the gym. This is anti-fragility.</p>
<p>Everyone know’s what <a target="_blank" href="https://www.mayoclinic.org/diseases-conditions/post-traumatic-stress-disorder/symptoms-causes/syc-20355967">P-T-S-D</a> is. However P-T-Growth is where you actually grow under pressure. This happens when you ‘Learn to fail or fail to learn’. You deliberately learn from your failures.</p>
<p>Happiness is a spectrum. It’s not binary. Some days are better than others which you’ve to push through.</p>
<p>Spiritual . Physical . Intellectual . Relationship . Emotional - (SPIRE) are the 5 dimensions of well being who’s tenets are the quality of our relationships tied in with gratitude and growth.</p>
<h2 id="heading-references">References</h2>
<ul>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=q6yPcEk93nk">Don't chase happiness. Become antifragile | Tal Ben-Shahar: Full Interview</a></p>
</li>
<li><p><a target="_blank" href="https://www.mayoclinic.org/diseases-conditions/post-traumatic-stress-disorder/symptoms-causes/syc-20355967">PTSD</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Gevent celery config I/O bound]]></title><description><![CDATA[When NOT using Gevent (worker_pool\=[prefork|gthread]), the number of concurrent workers defaults to the number of cores which are effectively the tasks that will be executing in “parallel”.
The prefetch multiplier (default 4) is an optimization to r...]]></description><link>https://blog.danwald.me/gevent-celery-config-io-bound</link><guid isPermaLink="true">https://blog.danwald.me/gevent-celery-config-io-bound</guid><category><![CDATA[async]]></category><category><![CDATA[Python]]></category><category><![CDATA[Threading]]></category><category><![CDATA[Event Loop]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Sat, 27 Dec 2025 09:16:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/iixVGC2dagw/upload/de16333e64d6b22b27e02560a79fa72d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When <strong>NOT</strong> using Gevent (<a target="_blank" href="https://docs.celeryq.dev/en/latest/userguide/configuration.html#worker-pool">worker_pool</a>\=[prefork|gthread]), the number of <a target="_blank" href="https://docs.celeryq.dev/en/latest/userguide/configuration.html#worker-concurrency">concurrent workers</a> defaults to the number of cores which are effectively the tasks that will be executing in “<a target="_blank" href="https://bytebytego.com/guides/concurrency-is-not-parallelism/">parallel</a>”.</p>
<p><a target="_blank" href="https://docs.celeryq.dev/en/latest/userguide/configuration.html#worker-prefetch-multiplier">The prefetch multiplier</a> (default 4) is an optimization to reduce round trips to the broker (queue), to eagerly fetch tasks at the node per available worker. This happens at the consumers not at the workers.</p>
<p>With 4 workers:</p>
<ul>
<li><p>16 tasks consumed</p>
</li>
<li><p>12 are <em>waiting</em> for an available worker</p>
</li>
<li><p>4 are being concurrently processed</p>
</li>
</ul>
<p>If you have short lived tasks this isn’t a problem. However if your workloads’ <strong>execution time varies</strong>, all task could potentially convoy on the same node and dramatically <strong>reducing the throughput per worker</strong>. It’s recommended to use a prefetch of 1 or 2 to reduce the effect.</p>
<p>If you strictly have <a target="_blank" href="https://en.wikipedia.org/wiki/I/O_bound">IO bound</a> tasks you should use <a target="_blank" href="https://docs.celeryq.dev/en/v5.5.3/userguide/concurrency/gevent.html">gevent</a>. Using cooperative multitasking via a coroutine mechanism, you can effectively have 100s of workers per worker which will all execute concurrently.</p>
<p>Some considerations:</p>
<ul>
<li><p>Use connection pooling for database or http access to avoid herding</p>
</li>
<li><p>monkey patch correctly</p>
</li>
<li><p>if the workload isn’t IO bound, you will run into issues with the <a target="_blank" href="https://wiki.python.org/moin/GlobalInterpreterLock">GIL</a>.</p>
</li>
</ul>
<p>Since python 3.14, <a target="_blank" href="https://docs.python.org/3.14/whatsnew/3.14.html#whatsnew314-free-threaded-now-supported">free threaded python is officially supported (phase 2)</a>. However it’s not production ready but it brings thread level parallelism to applications.</p>
<p>Happy Hackin’</p>
<h3 id="heading-references">References:</h3>
<ul>
<li><p><a target="_blank" href="https://docs.celeryq.dev/en/latest/userguide/configuration.html#worker-pool">worker_pool</a></p>
</li>
<li><p><a target="_blank" href="https://docs.celeryq.dev/en/latest/userguide/configuration.html#worker-concurrency">worker_concurrency</a></p>
</li>
<li><p><a target="_blank" href="https://bytebytego.com/guides/concurrency-is-not-parallelism/">Concurrency vs Parallelism</a></p>
</li>
<li><p><a target="_blank" href="https://docs.celeryq.dev/en/latest/userguide/configuration.html#worker-prefetch-multiplier">worker_prefetch_multiplier</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/I/O_bound">IO bound tasks</a></p>
</li>
<li><p><a target="_blank" href="https://docs.celeryq.dev/en/v5.5.3/userguide/concurrency/gevent.html">Gevent</a></p>
</li>
<li><p><a target="_blank" href="https://wiki.python.org/moin/GlobalInterpreterLock">GIL</a></p>
</li>
<li><p><a target="_blank" href="https://docs.python.org/3.14/whatsnew/3.14.html#whatsnew314-free-threaded-now-supported">Python free threads</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=Mp5wKOL4L2Q">Anthony Shaw’s talk on parallelism with python (sub-interpreters / free threads)</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Kafka considerations]]></title><description><![CDATA[Auto-commit - at most once delivery
When consumers are configured with auto-commit, the queue offset will commit on message delivery. If the process dies before processing, the message is effectively lost.
Manual commit - at least once delivery
When ...]]></description><link>https://blog.danwald.me/kafka-considerations</link><guid isPermaLink="true">https://blog.danwald.me/kafka-considerations</guid><category><![CDATA[queue]]></category><category><![CDATA[kafka]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Mon, 22 Dec 2025 16:52:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/HYcSWOYiWyE/upload/0a524d35173169a07f31497e84298e0b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-auto-commit-at-most-once-delivery">Auto-commit - at most once delivery</h3>
<p>When consumers are configured with auto-commit, the queue offset will commit on message delivery. If the process dies before processing, the message is effectively lost.</p>
<h3 id="heading-manual-commit-at-least-once-delivery">Manual commit - at least once delivery</h3>
<p>When manually committing messages which is done after processing occurs, if the process dies before committing, the message will be reprocessed by another consumer as the offset isn’t updated.</p>
<h3 id="heading-always-close-your-connections">Always close your connections</h3>
<p>Kafka consumers are run in a long running processes or maybe as a cronjob. The process connects to the configured cluster, topic and group. On exit, you need to explicitly close the connection. If not the topic/group will enter a rebalancing state where no messages can be read by existing consumers causing a delay in processing or even message loss.</p>
<h3 id="heading-rebalancing">Rebalancing</h3>
<p>When a consumer enters/leaves a group, dies or partitions are reassigned.</p>
<h3 id="heading-use-a-consumer-group">Use a consumer group</h3>
<p>It will load balance non overlapping messages across consumers, automatically assigns partitions and manage offsets. However there is chance of reprocessing of messages during rebalancing.</p>
<h3 id="heading-exactly-once-delivery">Exactly once delivery</h3>
<p>Can be configured at the server level, but drastically reduces throughput.</p>
<h3 id="heading-be-idempotent">Be idempotent</h3>
<p>Duplicate messages will be the norm. Use the strategies below to avoid reprocessing messages.</p>
<ul>
<li><p>Unique constraints on application tables</p>
</li>
<li><p>Unique constraints on separate message table</p>
</li>
<li><p>Use the outbox pattern when adding to the DB + producing a message</p>
</li>
<li><p>Redis deduplication with NX</p>
</li>
<li><p>Produce Application level messages with a unique ID</p>
</li>
</ul>
<h3 id="heading-dont-manually-assign-partitions">Don’t manually assign partitions</h3>
<p>This bypasses coordination across consumer group of a topic. The application has to manage conflicts.</p>
<h3 id="heading-static-members-to-avoid-rebalancing">Static members to avoid rebalancing</h3>
<p>You can specify a unique <code>group_instance_id</code> of each instance to avoid rebalancing and its effects. Can be managed via k8s.</p>
]]></content:encoded></item><item><title><![CDATA[5 Event-Driven Architecture Pitfalls to Avoid]]></title><description><![CDATA[I needed to understand the gotchas in event-driven architecture before migrating more services. Wix's engineering team documented 5 painful lessons learned from moving over 2300 microservices from request-reply to event-driven patterns.
The Pitfalls
...]]></description><link>https://blog.danwald.me/5-event-driven-architecture-pitfalls-to-avoid</link><guid isPermaLink="true">https://blog.danwald.me/5-event-driven-architecture-pitfalls-to-avoid</guid><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[Pitfalls]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Thu, 04 Dec 2025 03:43:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/wc3jFFQxo8k/upload/a50df64ccb0a486f9d8b3578bd281ae9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I needed to understand the gotchas in event-driven architecture before migrating more services. Wix's engineering team <a target="_blank" href="https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1">documented</a> 5 painful lessons learned from moving over 2300 microservices from request-reply to event-driven patterns.</p>
<h2 id="heading-the-pitfalls">The Pitfalls</h2>
<h3 id="heading-1-non-atomic-database-writes-and-event-publishing"><strong>1. Non-atomic database writes and event publishing</strong></h3>
<p>Writing to a database and firing an event isn't atomic. If either the DB or message broker fails, you get data inconsistency.</p>
<p>Solutions:</p>
<ul>
<li><p>Resilient producer that retries until the event reaches Kafka</p>
</li>
<li><p>CDC (Change Data Capture) with Debezium - captures DB changes via binlog and produces them as events automatically</p>
</li>
</ul>
<h3 id="heading-2-using-event-sourcing-everywhere"><strong>2. Using Event Sourcing everywhere</strong></h3>
<p>Event sourcing stores events instead of entity state. You reconstruct current state by replaying events. Sounds cool but adds serious complexity:</p>
<ul>
<li><p>Need snapshots to avoid performance degradation</p>
</li>
<li><p>Harder to create generic libraries (unlike CRUD ORMs)</p>
</li>
<li><p>Only eventual consistency</p>
</li>
</ul>
<p>Better approach: CRUD + CDC. Simple reads from the database, with CDC publishing changes for downstream materialized views. Get the benefits without the complexity.</p>
<h3 id="heading-3-no-context-propagation"><strong>3. No context propagation</strong></h3>
<p>Debugging distributed event flows is hard. Unlike HTTP chains, events scatter across topics and services.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Add request context to event headers</span>
event_headers = {
    <span class="hljs-string">'requestId'</span>: request_id,
    <span class="hljs-string">'userId'</span>: user_id
}
</code></pre>
<p>Automatically propagate these IDs through your event chain. Makes filtering logs and events trivial during incident investigation.</p>
<h3 id="heading-4-large-event-payloads"><strong>4. Large event payloads</strong></h3>
<p>Events over 5MB kill broker performance. Three remedies:</p>
<ul>
<li><p><strong>Compression</strong> - Kafka and Pulsar support lz4, snappy. Broker-level compression beats application-level</p>
</li>
<li><p><strong>Chunking</strong> - Split payloads into chunks with metadata for reassembly</p>
</li>
<li><p><strong>Object store reference</strong> - Store payload in S3, pass URL in event</p>
</li>
</ul>
<h3 id="heading-5-duplicate-event-processing"><strong>5. Duplicate event processing</strong></h3>
<p>Most brokers guarantee at-least-once delivery. Events can be processed multiple times.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Use optimistic locking with revisionId</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_event</span>(<span class="hljs-params">event</span>):</span>
    revision_id = event[<span class="hljs-string">'revisionId'</span>]
    <span class="hljs-comment"># Read current version</span>
    entity = db.get(event[<span class="hljs-string">'entityId'</span>])
    <span class="hljs-keyword">if</span> entity.revision_id != revision_id:
        <span class="hljs-keyword">return</span>  <span class="hljs-comment"># Already processed</span>

    <span class="hljs-comment"># Update with new revision</span>
    entity.update(revision_id=revision_id + <span class="hljs-number">1</span>)
</code></pre>
<p>For Kafka, use topic-partition-offset as unique transaction ID.</p>
<h2 id="heading-the-migration-strategy">The Migration Strategy</h2>
<p>Migrate gradually. Mix HTTP/RPC with event-driven patterns as needed. CDC is the sweet spot - ensures consistency without full event-sourcing complexity.</p>
<p>Context propagation (pitfall #3) is critical for operations. Fix that early.</p>
<p>Compression and transaction IDs are good defaults even if you don't hit pitfalls #4 and #5 yet.</p>
<p>Happy hackin'!</p>
<h2 id="heading-references"><strong>References:</strong></h2>
<ul>
<li><p><a target="_blank" href="https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1">Wix Engineering: Event Driven Architecture pitfalls</a></p>
</li>
<li><p><a target="_blank" href="https://debezium.io/documentation/reference/stable/architecture.html">Debezium: CDC Kafka connector</a></p>
</li>
<li><p><a target="_blank" href="https://debezium.io/blog/2023/02/04/ddd-aggregates-via-cdc-cqrs-pipeline-using-kafka-and-debezium/">DDD Aggregates via CDC-CQRS Pipeline using Kafka &amp; Debezium</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/wix/greyhound#greyhound">Greyhound: Wix messaging platform</a></p>
</li>
<li><p><a target="_blank" href="https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how-apache-kafka-does-it/">Kafka: Exactly once semantics</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[1+N querys]]></title><description><![CDATA[Widely know as N+plus one problem, it’s actually a misnomer. As @adamj.eu’s article neatly summarize with examples (and now my dyslexic mind actually understands it), it’s one query to get a list of N objects that you iterate over. And each iteration...]]></description><link>https://blog.danwald.me/1n-querys</link><guid isPermaLink="true">https://blog.danwald.me/1n-querys</guid><category><![CDATA[Django]]></category><category><![CDATA[Python]]></category><category><![CDATA[Databases]]></category><category><![CDATA[query-optimization]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Mon, 17 Nov 2025 03:32:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/5Pln0OGhrvc/upload/746733fb75070d475a02a515b8fb02b2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Widely know as N+plus one problem, it’s actually a misnomer. As <a target="_blank" href="https://bsky.app/profile/adamj.eu">@</a><a target="_blank" href="http://adamj.eu">adamj.eu</a>’s <a target="_blank" href="https://adamj.eu/tech/2020/09/01/django-and-the-n-plus-one-queries-problem/">article</a> neatly summarize with examples (and now my dyslexic mind actually understands it), it’s one query to get a list of N objects that you iterate over. And each iteration is a query as the initial query is lazy evaluated.</p>
<p>To avoid this in django, use:</p>
<ol>
<li><p><a target="_blank" href="https://docs.djangoproject.com/en/5.2/ref/models/querysets/#select-related">select_related</a> (for one-to-one or one-to-many queries)</p>
</li>
<li><p><a target="_blank" href="https://docs.djangoproject.com/en/5.2/ref/models/querysets/#prefetch-related">prefetch_related</a> (for many-to-many, many-to-one or generic-relations queries)</p>
</li>
</ol>
<p>where it gets the related rows with the initial query, as the name indicates.</p>
<p><em>Always try and minimize the queries to a shared resource.</em></p>
<p>Happy hackin’</p>
<h3 id="heading-referenhttpsbskyappprofileadamjeuces"><a target="_blank" href="https://bsky.app/profile/adamj.eu">Referen</a>ces:</h3>
<ul>
<li><p><a target="_blank" href="https://adamj.eu/tech/2020/09/01/django-and-the-n-plus-one-queries-problem/">Article: django and the n plus one queries problem</a></p>
</li>
<li><p><a target="_blank" href="https://docs.djangoproject.com/en/5.2/ref/models/querysets/#prefetch-related">Django: QuerySet:prefetch_related</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Alembic disables my logs]]></title><description><![CDATA[…and how to get them back
Alembic is SQLAlchemy's database migration framework—think change management for your relational database. It autogenerates scripts tracking your ORM model changes, letting you recreate your data model at any point in time.
...]]></description><link>https://blog.danwald.me/alembic-disables-my-logs</link><guid isPermaLink="true">https://blog.danwald.me/alembic-disables-my-logs</guid><category><![CDATA[Python]]></category><category><![CDATA[logging]]></category><category><![CDATA[Alembic]]></category><category><![CDATA[Missing]]></category><category><![CDATA[flask-sqlalchemy]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Sun, 12 Oct 2025 15:30:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/UsET4S0ginw/upload/4f335b40102ea45e7b69988e80c92799.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>…and how to get them back</strong></p>
<p>Alembic is SQLAlchemy's database migration framework—think change management for your relational database. It autogenerates scripts tracking your ORM model changes, letting you recreate your data model at any point in time.</p>
<p>Most apps run migrations on startup. I noticed my logs would mysteriously vanish right after the migration check.</p>
<p>The culprit? This innocent-looking snippet in the auto-generated <a target="_blank" href="http://env.py"><code>env.py</code></a>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">if</span> config.config_file_name <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span>:
    fileConfig(config.config_file_name)
</code></pre>
<p>That <code>fileConfig</code> defaults to <code>disable_existing_loggers=True</code> (thanks, <a target="_blank" href="https://docs.python.org/3/library/logging.config.html#logging.config.fileConfig">backwards compatibility!</a>), nuking any logging you previously configured.</p>
<p><strong>The fix:</strong> Either edit the generated <a target="_blank" href="http://env.py"><code>env.py</code></a> or configure your logging <em>after</em> migrations run.</p>
<p>Happy hackin'</p>
<h3 id="heading-references">References:</h3>
<ul>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/78780118/how-can-i-stop-the-alembic-logger-from-deactivating-my-own-loggers-after-using-a">Stackoverflow article</a></p>
</li>
<li><p><a target="_blank" href="https://alembic.sqlalchemy.org/en/latest/">Alembic</a></p>
</li>
<li><p><a target="_blank" href="https://www.sqlalchemy.org/">SQLAlchemy</a></p>
</li>
<li><p><a target="_blank" href="https://docs.python.org/3/library/logging.config.html#logging.config.fileConfig">loggging.config.fileConfig</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[DDD: Summary]]></title><description><![CDATA[Here is a summary / cliff’s notes of the Domain Driven Design Quickly eBook

Domain is what you trying to encode for which is owned by domain experts/specialist of the area

The domain model is an abs]]></description><link>https://blog.danwald.me/ddd-summary</link><guid isPermaLink="true">https://blog.danwald.me/ddd-summary</guid><category><![CDATA[#Domain-Driven-Design]]></category><category><![CDATA[architecture]]></category><category><![CDATA[Design]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Mon, 29 Sep 2025 17:14:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754724715565/5349e204-4d97-40a4-b3f0-877445e9f6ea.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here is a summary / cliff’s notes of the <a href="http://www.infoq.com/minibooks/domain-driven-design-quickly">Domain Driven Design Quickly</a> eBook</p>
<ul>
<li><p><strong>Domain</strong> is what you trying to encode for which is owned by domain experts/specialist of the area</p>
</li>
<li><p>The <strong>domain model</strong> is an <em>abstraction</em> represents the domain you’re trying to capture from the owners</p>
</li>
<li><p>The <em>domain model</em> should be described and communicated within a <strong>ubiquitous language</strong></p>
</li>
<li><p>An <strong>analyst model</strong> is independently derived from the domain not considering software and design</p>
</li>
<li><p><strong>Layers of DDD</strong>: <em>UI; Application; Domain; Infrastructure;</em></p>
</li>
<li><p><strong>Entities</strong> are <em>components</em> that have <em>identities</em> and are <em>mutable</em></p>
</li>
<li><p><strong>Value Objects</strong> are <em>immutable attributes</em> or <em>components</em> that enrich entities and immutable</p>
</li>
<li><p><strong>Aggregates</strong> is a single unit of change that own several entities of a domain model</p>
</li>
<li><p>An <strong>Aggregate root</strong> is an entity conduit for external requests policing change to a model</p>
</li>
<li><p><strong>Services</strong> provide functionally at the application level or domain level with Aggregates</p>
</li>
<li><p><strong>Factories</strong> are used to create complicated aggregates and tightly coupled to to the domain</p>
</li>
<li><p><strong>Repositories</strong> are an abstraction of storage, retrieval and reconstitution of entities, coupled with infrastructure</p>
</li>
<li><p><em>Iterative and continuous</em> <strong>Refactoring</strong> provide deeper insights, refine inconsistencies or missing components while avoiding a rigid design and improving to an incisive, deep model</p>
</li>
<li><p>Make <strong>constraints</strong> (invariables), <strong>process</strong> (methods or services) and (composable) <strong>specifications</strong> explicit</p>
</li>
<li><p>A <strong>Bounded Context</strong> is a logical frame allowing model evolution, isolation by module, team, code and DB schemas. CI fosters independent, pure and unified growth but doesn’t handle Inter-model relationships which should be well defined</p>
</li>
<li><p>A <strong>Context Map</strong> show relationships between bounded contexts capture the whole unified domain model</p>
</li>
<li><p>To reduce duplication, a <strong>Shared Kernel</strong> is a overlapping subset of the domain model shared by teams</p>
</li>
<li><p>Establish a <strong>Customer/Supplier</strong> relationship between dependent teams with the former defining integration tests for the latter to improve speed</p>
</li>
<li><p><strong>Conformist</strong> are customers that work within a one-sided supplier relationship building on a model that’s given provided there is a rich interface that fulfill their needs.</p>
</li>
<li><p>An <strong>Anticorruption layer</strong> is a proxy between our clients and a 3rd party (legacy) systems. It’s usually implemented with <strong>Facades</strong> that our clients interface with which internally use their own adapters with translators to facilitate inter system communication and maintain separation and purity</p>
</li>
<li><p>A <strong>separate ways</strong> strategy is employed to split an application that has disparate bounded contexts</p>
</li>
<li><p>An <strong>open host service</strong> wraps a external service as a set of services made available to several of our clients that use it. The protocol is open and avoids a translator per client. Esoteric clients can have a translator to the protocol</p>
</li>
<li><p><strong>Distillation</strong> separates the essential parts of a large domain from generic sub domains used is several places. The core distillation is iterative and should be the main focus. Sub domains can use off the shelf solutions, be outsourced, use existing models or an in house solution</p>
</li>
</ul>
<p>References:</p>
<ul>
<li><p><a href="http://www.infoq.com/minibooks/domain-driven-design-quickly">http://www.infoq.com/minibooks/domain-driven-design-quickly</a></p>
</li>
<li><p><a href="https://domaindrivendesign.org/">https://domaindrivendesign.org/</a></p>
</li>
<li><p><a href="https://amzn.to/3J3z1Th">Domain Design Design Book</a></p>
</li>
<li><p><a href="https://claude.ai/public/artifacts/8eb6d485-0e8d-4fd1-869b-de5ae075b07f">Main image via Claude</a></p>
</li>
</ul>
<hr />
<blockquote>
<p>This article is part of the <a href="https://blog.danwald.me/series/system-design">system design series</a> where I am summarizing chapters from The System Design Interview: <a href="https://www.amazon.ae/Independently-Published-System-Design-Interview/dp/B08CMF2CQF">Volume 1</a> / <a href="https://www.amazon.ae/System-Design-Interview-Insiders-Guide/dp/1736049119">Volume 2</a> amongst other related content</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Celery gotchas]]></title><description><![CDATA[Async Reliability with Celery
Task Loss Prevention Between Web Process and Broker

Enable broker confirmation: Configure confirm_publish on RabbitMQ to ensure tasks are actually committed to the broker before the delay operation completes

Pass data ...]]></description><link>https://blog.danwald.me/celery-gotchas</link><guid isPermaLink="true">https://blog.danwald.me/celery-gotchas</guid><category><![CDATA[Python]]></category><category><![CDATA[celery]]></category><category><![CDATA[gotchas]]></category><category><![CDATA[best practices]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Sat, 06 Sep 2025 12:43:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/vEKmpUC7wbA/upload/7d51a017fc86ef57493453e5799f4a2f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-async-reliability-with-celeryhttpswwwyoutubecomwatchvvuonif99oqc"><a target="_blank" href="https://www.youtube.com/watch?v=VuONiF99Oqc">Async Reliability with Celery</a></h2>
<h3 id="heading-task-loss-prevention-between-web-process-and-broker">Task Loss Prevention Between Web Process and Broker</h3>
<ul>
<li><p><strong>Enable broker confirmation</strong>: Configure <code>confirm_publish</code> on RabbitMQ to ensure tasks are actually committed to the broker before the delay operation completes</p>
</li>
<li><p><strong>Pass data references, not data values</strong>: Use S3 URLs or database IDs instead of passing large Python objects as task arguments to prevent gigantic tasks that can crash workers</p>
</li>
<li><p><strong>Implement database-sourced task recovery</strong>: Use Celery Beat with periodic tasks that check the database and re-queue missed tasks (e.g., verification emails) for automatic recovery</p>
</li>
</ul>
<h3 id="heading-task-loss-prevention-between-broker-and-worker">Task Loss Prevention Between Broker and Worker</h3>
<ul>
<li><p><strong>Set</strong> <code>task_acks_late = True</code>: Tasks remain on the broker until the worker acknowledges completion, enabling redelivery if workers crash</p>
</li>
<li><p><strong>Use</strong> <code>transaction.on_commit()</code>: Only queue tasks after database transactions commit to avoid race conditions where tasks execute before data is saved</p>
</li>
<li><p><strong>Make tasks idempotent</strong>: Use ORM methods like <code>get_or_create()</code> and <code>update_or_create()</code> so tasks can be safely retried multiple times</p>
</li>
<li><p><strong>Wrap tasks in</strong> <code>transaction.atomic()</code>: Ensure database changes can be rolled back if tasks are interrupted</p>
</li>
</ul>
<h3 id="heading-worker-reliability-configuration">Worker Reliability Configuration</h3>
<ul>
<li><p><strong>Set</strong> <code>task_reject_on_worker_lost = True</code>: Enable task redelivery even when workers die from memory errors or SIGKILL signals</p>
</li>
<li><p><strong>Handle all exceptions properly</strong>: Treat task exceptions with the same care as 500 errors in web views, using Celery's retry functionality for intermittent failures</p>
</li>
<li><p><strong>Use RabbitMQ over Redis/SQS</strong>: RabbitMQ's connection-based redelivery is more reliable than visibility timeout mechanisms</p>
</li>
</ul>
<h3 id="heading-deployment-safety">Deployment Safety</h3>
<ul>
<li><p><strong>Empty queues before changing task signatures</strong>: Ensure no old tasks remain when modifying function parameters</p>
</li>
<li><p><strong>Avoid ETA/countdown tasks beyond a few seconds</strong>: These live in worker memory and complicate deployments</p>
</li>
<li><p><strong>Use graceful shutdown (SIGTERM)</strong>: Avoid SIGKILL during deploys to prevent unintended task dropping</p>
</li>
</ul>
<h3 id="heading-alternative-approaches">Alternative Approaches</h3>
<ul>
<li><p><strong>Use dedicated workflow tools for complex orchestration</strong>: Consider Prefect, Temporal, or Airflow instead of Celery Canvas for complex workflows</p>
</li>
<li><p><strong>Implement proper monitoring and alerting</strong>: Set up observability tools specifically for Celery task execution</p>
</li>
<li><p><strong>Configure task time limits and expiration</strong>: Prevent clogged queues and outdated notifications</p>
</li>
</ul>
<h2 id="heading-celery-canvas-best-practiceshttpsgithubcomtobiasmcnultycelerycanvas"><a target="_blank" href="https://github.com/tobiasmcnulty/celery_canvas">Celery Canvas Best Practices</a></h2>
<h3 id="heading-workflow-patterns-demonstrated"><strong>Workflow Patterns Demonstrated</strong></h3>
<ul>
<li><p><strong>Single Sequential Task (</strong><code>all_in_one</code>): Processes all work in one task iterating through items sequentially - simplest but not parallel</p>
</li>
<li><p><strong>Parallel Tasks with Join</strong>: Queues multiple tasks simultaneously but demonstrates why you should <strong>never call</strong> <code>result.get()</code> within a task - causes RuntimeError</p>
</li>
<li><p><strong>Chord Pattern</strong>: Uses <code>chord</code> to run parallel tasks and execute a callback after all complete - recommended for fan-out/fan-in workflows</p>
</li>
<li><p><strong>Starmap for Parameter Mapping</strong>: Uses <code>starmap</code> to efficiently map function calls over parameter tuples</p>
</li>
<li><p><strong>Fine-grained Parallelism</strong>: Shows how to break work into smaller parallel tasks for maximum throughput</p>
</li>
</ul>
<h3 id="heading-performance-and-scalability-insights"><strong>Performance and Scalability Insights</strong></h3>
<ul>
<li><p><strong>Database-intensive work</strong>: Parallel task execution isn't always better - database query optimization often outperforms more concurrent tasks for DB-heavy operations</p>
</li>
<li><p><strong>Task granularity matters</strong>: Breaking work into smaller tasks enables better parallelism but creates more overhead</p>
</li>
<li><p><strong>Concurrency configuration</strong>: Use appropriate worker concurrency settings (example shows <code>-c 8</code>) based on your workload</p>
</li>
</ul>
<h3 id="heading-canvas-primitives-usage"><strong>Canvas Primitives Usage</strong></h3>
<ul>
<li><p><strong>Chord</strong>: Best for fan-out/fan-in patterns where you need to collect results after parallel execution</p>
</li>
<li><p><strong>Starmap</strong>: Efficient for mapping a function over multiple parameter sets</p>
</li>
<li><p><strong>Group</strong>: For simple parallel execution without result collection</p>
</li>
<li><p><strong>Chain</strong>: For sequential task dependencies</p>
</li>
</ul>
<h3 id="heading-setup-and-configuration-best-practices"><strong>Setup and Configuration Best Practices</strong></h3>
<ul>
<li><p><strong>Use RabbitMQ as broker</strong>: The examples use RabbitMQ via Docker for reliable message delivery</p>
</li>
<li><p><strong>Environment isolation</strong>: Uses <code>direnv</code> for clean Python virtual environment management</p>
</li>
<li><p><strong>Mac-specific configuration</strong>: Sets <code>OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES</code> for multithreading compatibility</p>
</li>
<li><p><strong>Proper worker scaling</strong>: Configure concurrency based on workload characteristics</p>
</li>
</ul>
<h3 id="heading-performance-testing-approach"><strong>Performance Testing Approach</strong></h3>
<ul>
<li><p><strong>Comparative benchmarking</strong>: The repository demonstrates multiple approaches to the same problem for performance comparison</p>
</li>
<li><p><strong>Real-world simulation</strong>: Uses a voter registration scenario with 10,000 records to test scalability</p>
</li>
<li><p><strong>Timing analysis</strong>: Encourages comparing timestamps to measure actual performance differences</p>
</li>
</ul>
<h3 id="heading-key-takeaway"><strong>Key Takeaway</strong></h3>
<p>The repository emphasizes that <strong>Canvas primitives should be used judiciously</strong> - parallel execution isn't always faster, especially for database-intensive operations. The choice between sequential, parallel, or Canvas-based approaches should be based on the specific nature of your workload and performance testing results.</p>
<h2 id="heading-references">References</h2>
<ul>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=VuONiF99Oqc">Mixing reliability with Celery for delicious async tasks with Flávio Juvenal (DjangoCon US '23)</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/tobiasmcnulty/celery_canvas">Celery canvas best practices</a></p>
</li>
<li><p><a target="_blank" href="https://gist.github.com/fjsj/da41321ac96cf28a96235cb20e7236f6">Recommended celery settings</a></p>
</li>
</ul>
<h2 id="heading-celery-links-amp-best-practices">Celery links &amp; best practices:</h2>
<ul>
<li><p><a target="_blank" href="https://docs.celeryq.dev/en/stable/userguide/configuration.html">Official Celery Configuration Docs</a></p>
</li>
<li><p><a target="_blank" href="https://bit.ly/celery-reliability">Celery Reliability</a></p>
</li>
<li><p><a target="_blank" href="https://denibertovic.com/posts/celery-best-practices/">Celery best practices</a></p>
</li>
<li><p><a target="_blank" href="https://medium.com/squad-engineering/celery-in-production-three-more-years-of-fixing-bugs-2ee462cef39f">Celery in production - fixing bugs</a></p>
</li>
<li><p><a target="_blank" href="https://engineering.instawork.com/celery-eta-tasks-demystified-424b836e4e94">Celery eta tasks demystified</a></p>
</li>
<li><p><a target="_blank" href="https://blog.wolt.com/engineering/2021/09/15/5-tips-for-writing-production-ready-celery-tasks/">5 tips for writing production ready celery tasks</a></p>
</li>
<li><p><a target="_blank" href="https://adamj.eu/tech/2020/02/03/common-celery-issues-on-django-projects/">Common celery issues on django projects</a></p>
</li>
<li><p><a target="_blank" href="https://blog.daftcode.pl/working-with-asynchronous-celery-tasks-lessons-learned-32bb7495586b">Working with asynchronous celery tasks</a></p>
</li>
<li><p><a target="_blank" href="https://italux.medium.com/celery-rabbitmq-common-issues-a741a3800b30">Celery / rabbitmq common issues</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/66978028/application-impacts-of-celery-workers-running-with-the-without-heartbeat-fla">Celery workers without heartbeat</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Moving Git history]]></title><description><![CDATA[I needed to move some files between two repositories. I could have just copied the files over but I wanted to maintain the commit history.
Enter the git-filter-repo utility that’s based on the native git-filter-branch command. It does a lot of things...]]></description><link>https://blog.danwald.me/moving-git-history</link><guid isPermaLink="true">https://blog.danwald.me/moving-git-history</guid><category><![CDATA[Git]]></category><category><![CDATA[commit]]></category><category><![CDATA[history]]></category><category><![CDATA[save]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Tue, 05 Aug 2025 10:17:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/RGJlwpeAIBg/upload/51e30e07e0355def915031d3c6a48c10.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I needed to move some files between two repositories. I could have just copied the files over but I wanted to maintain the commit history.</p>
<p>Enter the <a target="_blank" href="https://github.com/newren/git-filter-repo">git-filter-repo</a> utility that’s based on the native <a target="_blank" href="https://git-scm.com/docs/git-filter-branch">git-filter-branch</a> command. It does a lot of things but for my use case I only filtered for the folder I need moved.</p>
<p>Here’s what I did:</p>
<h3 id="heading-prepare-your-source-repository">Prepare your source repository</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># RE-Clone the source repository (local version will be altered)</span>
git <span class="hljs-built_in">clone</span> /path/to/source-repo source-repo-filtered 
<span class="hljs-built_in">cd</span> source-repo-filtered 

<span class="hljs-comment"># Extract only the directory you want (keeps full history)</span>
git filter-repo --path directory-to-move/

<span class="hljs-comment"># Optional: Remove the directory prefix if you want it at the root</span>
git filter-repo --path-rename directory-to-move/:
</code></pre>
<blockquote>
<p>filtering will remove all other git objects</p>
</blockquote>
<h3 id="heading-prepare-the-destination-repository">Prepare the destination repository</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># Clone or navigate to your destination repository</span>
git <span class="hljs-built_in">clone</span> /path/to/destination-repo destination-repo
<span class="hljs-built_in">cd</span> destination-repo

<span class="hljs-comment"># Add the local filtered repository as a remote</span>
git remote add source-filtered /path/to/source-repo-filtered

<span class="hljs-comment"># Fetch the filtered history</span>
git fetch source-filtered
</code></pre>
<h3 id="heading-merge-into-the-destination-repository">Merge into the destination repository</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># Create a new branch for the merge</span>
git checkout -b merge-directory

<span class="hljs-comment"># Merge the filtered history (allows unrelated histories)</span>
git merge source-filtered/main --allow-unrelated-histories

<span class="hljs-comment"># If you want the directory in a specific location, you might need additional renaming</span>
<span class="hljs-comment"># For example, to put it in a subdirectory:</span>
git filter-repo --path-rename :new-location/
</code></pre>
<blockquote>
<p>review the branch before you merge</p>
</blockquote>
<h3 id="heading-clean-up-the-destination-repository">Clean up the destination repository</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># Remove the temporary remote</span>
git remote remove source-filtered

<span class="hljs-comment"># Clean up the filtered repository clone</span>
rm -rf /path/to/source-repo-filtered

<span class="hljs-comment"># Clone the source repository again</span>
git <span class="hljs-built_in">clone</span> /path/to/source-repo source-repo-filtered 
<span class="hljs-built_in">cd</span> source-repo-filtered 

<span class="hljs-comment"># Delete a moved folder</span>
git filter-repo --path directory-moved/ --invert-paths

<span class="hljs-comment"># update the remote</span>
git push --force
</code></pre>
<h2 id="heading-references">References:</h2>
<ul>
<li><p><a target="_blank" href="https://github.com/newren/git-filter-repo">https://github.com/newren/git-filter-repo</a></p>
</li>
<li><p><a target="_blank" href="https://git-scm.com/docs/git-filter-branch">https://git-scm.com/docs/git-filter-branch</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Typing]]></title><description><![CDATA[We type almost every day. So going with xkcd’s “is it worth your time?”, it’s definitely is!

The effort you put in will compound and will leave you more time.
Given the improvements with AI text generation, it might seem like a fools errand. There a...]]></description><link>https://blog.danwald.me/typing</link><guid isPermaLink="true">https://blog.danwald.me/typing</guid><category><![CDATA[speed]]></category><category><![CDATA[typing]]></category><category><![CDATA[improvement]]></category><category><![CDATA[self-improvement ]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Sun, 27 Jul 2025 09:41:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/-EnI0H6Wm6s/upload/5b8d181a679dce3a70eac335e82fea33.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We type almost every day. So going with <a target="_blank" href="https://xkcd.com/1205/">xkcd</a>’s “is it worth your time?”, it’s definitely is!</p>
<p><a target="_blank" href="https://xkcd.com/1205/"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752724186562/0c4a8932-29ec-4ba9-a42c-49a4521c4750.png" alt class="image--center mx-auto" /></a></p>
<p>The effort you put in will compound and will leave you <em>more time.</em></p>
<p>Given the improvements with AI text generation, it might seem like a fools errand. There are situations where you still type and you’ll need to key in the prompts at the very least.</p>
<h3 id="heading-how">How</h3>
<p>Watch: <a target="_blank" href="https://www.youtube.com/watch?v=tU_AXrvQjpo">Full Course - How to Type 3x Faster</a> by <a target="_blank" href="https://aliabdaal.com/">Ali Abdaal</a>. It’s where I got most of the tools to start me on my improvement (<a target="_blank" href="https://www.keybr.com/profile/8225lmi">1</a>) (<a target="_blank" href="https://10fastfingers.com/user/4179830/">2</a>) journey</p>
<p>You need to make <a target="_blank" href="https://www.keybr.com/">https://www.keybr.com/</a> and <a target="_blank" href="https://10fastfingers.com/typing-test/english">https://10fastfingers.com/typing-test/english</a> part or you daily 15 minute routine and get faster at typing!</p>
<h2 id="heading-references">References:</h2>
<ul>
<li><p><a target="_blank" href="https://xkcd.com/1205/">XKCD: Is It worth your time?</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=tU_AXrvQjpo">Full Course - How to Type 3x Faster</a></p>
</li>
<li><p><a target="_blank" href="https://aliabdaal.com/">Ali Abdaal</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Nested ModuleNotFound]]></title><description><![CDATA[sys.path is a list of directories (or zip archives) to find imports. “The first entry in the module search path is the directory that contains the input script … Otherwise it’s the current directory”*
With the following project layout:
|- main.py #fr...]]></description><link>https://blog.danwald.me/nested-modulenotfound</link><guid isPermaLink="true">https://blog.danwald.me/nested-modulenotfound</guid><category><![CDATA[module not found]]></category><category><![CDATA[Python]]></category><category><![CDATA[virtual environment]]></category><category><![CDATA[modulenotfounderror]]></category><dc:creator><![CDATA[Danny Crasto]]></dc:creator><pubDate>Sat, 12 Jul 2025 12:33:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/eBkEJ9cH5b4/upload/af1b4093d0ce499e388ab416dfcbc942.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><code>sys.path</code> is a list of directories (or zip archives) to find imports. “The first entry in the module search path is the directory that contains the input script … Otherwise it’s the current directory”<a target="_blank" href="https://docs.python.org/3/library/sys_path_init.html">*</a></p>
<p>With the following project layout:</p>
<pre><code class="lang-bash">|- main.py <span class="hljs-comment">#from tools import tools. OK!</span>
|- tools <span class="hljs-comment"># module</span>
   | __init__.py
   | tools.py
|- scripts
   | __init__.py
   | use_tools.py <span class="hljs-comment">#from tools import tools **ModuleNotFoundError: No module named 'tools'</span>
|- .venv <span class="hljs-comment">#virtual env directory</span>
</code></pre>
<p><code>main.py</code> and <code>scripts/use_tools.py</code> both import from <code>tools/tools.py</code></p>
<p>However only <code>python scripts/use_tools.py</code> results in a <code>ModuleNotFoundError</code>. Below are the search paths when executing the script.</p>
<pre><code class="lang-bash">sys.path = [
    <span class="hljs-string">'~/sandbox/courses/langchain/ice_breaker/scripts'</span>, <span class="hljs-comment">#directory of input script</span>
    <span class="hljs-string">'~/.asdf/installs/python/3.13.2/lib/python313.zip'</span>, <span class="hljs-comment">#stdlib</span>
    <span class="hljs-string">'~/.asdf/installs/python/3.13.2/lib/python3.13'</span>, <span class="hljs-comment">#stdlib</span>
    <span class="hljs-string">'~/.asdf/installs/python/3.13.2/lib/python3.13/lib-dynload'</span>, <span class="hljs-comment">#stdlib</span>
    <span class="hljs-string">'~/sandbox/courses/langchain/ice_breaker/.venv/lib/python3.13/site-packages'</span> <span class="hljs-comment">#venv</span>
]
</code></pre>
<p>Python will search for the <code>tools</code> module in</p>
<ol>
<li><p>current working directory of the source file i.e. <code>scripts</code></p>
</li>
<li><p>check <code>PYTHONPATH</code></p>
</li>
<li><p>lastly, it will check python installation specific directories and activated virtualenv paths for standard-libs and site-packages (always use one)</p>
</li>
</ol>
<p>To fix the issue you can use <a target="_blank" href="https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH">PYTHONPATH</a> environment variable to add additional directories to <code>sys.path</code>.</p>
<p>Here it’s being done in the virtual environment’s <code>activate</code> script</p>
<pre><code class="lang-bash"><span class="hljs-comment"># .venv/bin/activate </span>

<span class="hljs-function"><span class="hljs-title">deactivate</span></span> () {
    <span class="hljs-comment"># reset old environment variables</span>
    <span class="hljs-keyword">if</span> [ -n <span class="hljs-string">"<span class="hljs-variable">${_OLD_VIRTUAL_PYTHONPATH:-}</span>"</span> ] ; <span class="hljs-keyword">then</span>
        PATH=<span class="hljs-string">"<span class="hljs-variable">${_OLD_VIRTUAL_PYTHONPATH:-}</span>"</span>
        <span class="hljs-built_in">export</span> PATH
        <span class="hljs-built_in">unset</span> _OLD_VIRTUAL_PYTHONPATH
    <span class="hljs-keyword">fi</span>
}

_OLD_VIRTUAL_PYTHONPATH=<span class="hljs-string">"<span class="hljs-variable">$PYTHONPATH</span>"</span>
<span class="hljs-built_in">export</span> PYTHONPATH=<span class="hljs-string">"<span class="hljs-variable">$PWD</span>:<span class="hljs-variable">$PYTHONPATH</span>"</span>
</code></pre>
<p>May your modules now be found.</p>
<p>Happy hackin’w</p>
<h2 id="heading-references">References</h2>
<ul>
<li><p><a target="_blank" href="https://docs.python.org/3/library/sys_path_init.html">The initialization of the sys.path module search path</a></p>
</li>
<li><p><a target="_blank" href="https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH">PYTHONPATH</a></p>
</li>
</ul>
]]></content:encoded></item></channel></rss>