<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>pythonstrup</title><description>pythonstrup — notes from a journey of growing one step at a time.</description><link>https://pythonstrup.com/</link><language>en</language><atom:link href="https://pythonstrup.com/rss.xml" rel="self" type="application/rss+xml"/><item><title>MCP Servers Were Eating 6.7GB of My RAM, So I Built a Proxy</title><link>https://pythonstrup.com/blog/23/</link><guid isPermaLink="true">https://pythonstrup.com/blog/23/</guid><description>stdio MCP servers duplicated per session added up to 169 processes and 6.7GB of RSS. I built a proxy to share one process across sessions — and finished with a bigger question. Do these servers still need to be MCP at all?</description><pubDate>Wed, 12 Aug 2026 12:00:00 GMT</pubDate><category>mcp</category><category>claude</category><category>llm</category></item><item><title>Passwordless DB Access and Least Privilege - IRSA, rds_iam, ALTER DEFAULT PRIVILEGES</title><link>https://pythonstrup.com/blog/24/</link><guid isPermaLink="true">https://pythonstrup.com/blog/24/</guid><description>How a Kubernetes pod connects to a database with no password anywhere (IRSA and rds_iam), and how the account that connects keeps its privileges minimal (owner separation and default privileges).</description><pubDate>Thu, 06 Aug 2026 13:00:00 GMT</pubDate><category>postgresql</category><category>kubernetes</category><category>security</category></item><item><title>Running a Notification System with BullMQ, Part 3 - Where to Store Delivery History</title><link>https://pythonstrup.com/blog/22/</link><guid isPermaLink="true">https://pythonstrup.com/blog/22/</guid><description>Where should delivery history live? The trade-offs weighed across a dedicated relational DB, a serial S3 pipeline, SNS fan-out, and a Firehose route.</description><pubDate>Sat, 25 Jul 2026 12:00:00 GMT</pubDate><category>BullMQ</category><category>nodejs</category><category>aws</category><category>architecture</category></item><item><title>Running a Notification System with BullMQ, Part 2 - Rate Limits and the Design They Forced</title><link>https://pythonstrup.com/blog/21/</link><guid isPermaLink="true">https://pythonstrup.com/blog/21/</guid><description>The sending quota was 100 messages per 5 seconds and our average was 20 req/s. On paper we were inside the limit, yet 429s kept appearing. Two fixed windows whose start times were not aligned turned out to be the cause, and the fact that another team shared the same third-party account pushed us to redesign the sending path itself.</description><pubDate>Mon, 20 Jul 2026 12:00:00 GMT</pubDate><category>BullMQ</category><category>nodejs</category><category>redis</category><category>typescript</category><category>rate limit</category></item><item><title>Recompute, Don’t Increment: Updating Review Statistics with RabbitMQ</title><link>https://pythonstrup.com/blog/19/</link><guid isPermaLink="true">https://pythonstrup.com/blog/19/</guid><description>How I separated review mutations from statistics calculation, then had a Review Consumer recompute statistics from the data available when each RabbitMQ event was processed. This article also covers functional idempotency and the message-loss windows that remained.</description><pubDate>Fri, 17 Jul 2026 12:25:00 GMT</pubDate><category>Kotlin</category><category>Spring</category><category>RabbitMQ</category><category>message queue</category><category>idempotency</category></item><item><title>Operating a Notification System with BullMQ, Part 1: What Is BullMQ?</title><link>https://pythonstrup.com/blog/20/</link><guid isPermaLink="true">https://pythonstrup.com/blog/20/</guid><description>Every service needs to send messages to users, whether through AlimTalk, email, or push notifications. But implementing notification delivery as a simple HTTP call quickly runs into limits. Each problem can be solved with another tool: consolidate delivery into one module, enforce a rate limit inside the function, create timing branches with a scheduler, and record delivery…</description><pubDate>Mon, 18 May 2026 14:35:46 GMT</pubDate><category>BullMQ</category><category>nodejs</category><category>redis</category><category>typescript</category></item><item><title>Why Kubernetes Kills My Pod: Health Probes</title><link>https://pythonstrup.com/blog/18/</link><guid isPermaLink="true">https://pythonstrup.com/blog/18/</guid><description>Kubernetes provides two kinds of probes for determining a Pod&apos;s state. A liveness probe asks, &quot;Is this container alive?&quot; The kubelet periodically calls a configured endpoint and restarts the container if the call fails or receives no response. This automatically recovers an application that has become unresponsive because of a deadlock or memory leak.</description><pubDate>Tue, 17 Mar 2026 15:08:15 GMT</pubDate><category>Health Check</category><category>k8s</category><category>kubernetes</category><category>terminus</category></item><item><title>2025 Retrospective</title><link>https://pythonstrup.com/blog/17/</link><guid isPermaLink="true">https://pythonstrup.com/blog/17/</guid><description>I believed that strong technical skills were all that mattered: clean code, refactoring, TDD, and domain-driven design. I kept practicing because I thought writing good code was a developer&apos;s highest virtue. Then the AI era shook that assumption. I realized that writing code well is no longer enough to create irreplaceable value. So what should developers truly focus on?</description><pubDate>Tue, 17 Feb 2026 05:20:34 GMT</pubDate><category>2025</category><category>developer</category><category>goals</category><category>retrospective</category></item><item><title>Reducing CDN Costs with Browser Caching</title><link>https://pythonstrup.com/blog/16/</link><guid isPermaLink="true">https://pythonstrup.com/blog/16/</guid><description>Have you ever introduced a CDN only to find the monthly cost burdensome? Our team cut more than one million won in annual CDN costs through browser-cache configuration alone. All it took was setting the Cache-Control header correctly. This article explains the fundamentals of CDNs and Cache-Control, then shares how we used browser caching to reduce costs in practice.</description><pubDate>Sat, 22 Nov 2025 09:05:57 GMT</pubDate><category>Cache-Control</category><category>CDN</category><category>ncloud</category><category>browser cache</category></item><item><title>A Ticketing System That Can Theoretically Handle 100,000 QPS</title><link>https://pythonstrup.com/blog/15/</link><guid isPermaLink="true">https://pythonstrup.com/blog/15/</guid><description>An event is being held to celebrate a celebrity&apos;s visit, with tickets available only to the first 1,000 people. Applications will be accepted through a web application. Suppose you protect the system with a distributed lock. Are you confident that concurrency is now completely under control?</description><pubDate>Wed, 05 Nov 2025 13:04:44 GMT</pubDate><category>java</category><category>redis</category><category>Spring</category><category>concurrency control</category></item><item><title>Setting Up NestJS to Fit Your Preferences</title><link>https://pythonstrup.com/blog/14/</link><guid isPermaLink="true">https://pythonstrup.com/blog/14/</guid><description>&quot;NestJS boilerplate&quot; is a search term almost everyone new to NestJS has probably tried at least once. But when you actually inspect the code, it is hard to tell what everything does or whether you need all of it.</description><pubDate>Sun, 26 Oct 2025 06:22:53 GMT</pubDate><category>Backend</category><category>javascript</category><category>nest</category><category>nestjs</category><category>nvm</category><category>tsconfig</category><category>typescript</category></item><item><title>Separating Concurrency Control Code with AOP</title><link>https://pythonstrup.com/blog/13/</link><guid isPermaLink="true">https://pythonstrup.com/blog/13/</guid><description>This article shows how to use Spring AOP to separate distributed-lock handling completely from business logic. When you use the Lock interface for concurrency control, try-finally blocks and lock-management code can overwhelm the business logic. Just as Spring&apos;s @Transactional simplifies transaction management, we will solve this problem with a DistributedLock aspect and extend @DistributedLock with a SpEL evaluator modeled after Spring Cache.</description><pubDate>Sun, 12 Oct 2025 07:23:49 GMT</pubDate><category>AOP</category><category>Aspect</category><category>spel</category><category>Spring</category><category>distributed lock</category></item><item><title>Myths and Facts About Lettuce Distributed Locks (feat. RedisLockRegistry)</title><link>https://pythonstrup.com/blog/9/</link><guid isPermaLink="true">https://pythonstrup.com/blog/9/</guid><description>This article continues from the previous post, &quot;Understanding Pessimistic Locks Through a Like Feature.&quot; It corrects the misconception that &quot;Lettuce supports only spin locks&quot; and explains how Spring RedisLockRegistry&apos;s Pub/Sub lock mode can implement an efficient distributed lock without Redisson.</description><pubDate>Mon, 29 Sep 2025 04:41:16 GMT</pubDate><category>java</category><category>lettuce</category><category>LockRegistry</category><category>redis</category><category>RedisLockRegistry</category><category>Spring</category><category>distributed lock</category></item><item><title>Understanding Pessimistic Locks Through a Like Feature</title><link>https://pythonstrup.com/blog/12/</link><guid isPermaLink="true">https://pythonstrup.com/blog/12/</guid><description>This article follows the process of solving the concurrency problems in a like feature with database locks. It explains how pessimistic locking works and examines the performance degradation caused by next-key locks.</description><pubDate>Sun, 28 Sep 2025 11:36:03 GMT</pubDate><category>java</category><category>redis</category><category>RedisLockRegistry</category><category>Spring</category><category>concurrency control</category><category>pessimistic locking</category></item><item><title>Relearning Java Concurrency Control from the Ground Up</title><link>https://pythonstrup.com/blog/11/</link><guid isPermaLink="true">https://pythonstrup.com/blog/11/</guid><description>This article explores how the JVM monitor behind synchronized actually works, examines the concurrency-control features provided by ReentrantLock, and solves the producer-consumer problem that can arise in concurrent programs. It then improves performance with a lock-striping strategy based on per-user keys.</description><pubDate>Tue, 23 Sep 2025 11:49:00 GMT</pubDate><category>java</category><category>JVM</category><category>lock striping</category><category>ReentrantLock</category><category>Spring</category><category>Synchronized</category><category>concurrency</category><category>monitor lock</category><category>producer-consumer problem</category></item><item><title>How an External API Nearly Brought Down Our Service: Adopting Virtual Threads</title><link>https://pythonstrup.com/blog/10/</link><guid isPermaLink="true">https://pythonstrup.com/blog/10/</guid><description>This article traces how I diagnosed thread blocking caused by network I/O and found a fundamental solution with JDK 21 virtual threads. Beyond the initial fix, it examines the unexpected challenges of thread pinning and overwhelming that emerged during adoption, along with their solutions.</description><pubDate>Sat, 20 Sep 2025 07:05:37 GMT</pubDate><category>Blocking IO</category><category>java</category><category>JVM</category><category>non-blocking io</category><category>Platform Thread</category><category>Spring</category><category>virtual thread</category><category>Virtual Threads</category></item><item><title>Nexters 27th Cohort Retrospective: Experiments Over Theory, and the Users Had the Answers</title><link>https://pythonstrup.com/blog/8/</link><guid isPermaLink="true">https://pythonstrup.com/blog/8/</guid><description>During Nexters&apos; 26th cohort, I was fixated on scenarios in my own head rather than on users. As the PM, I started the project with the slogan below. Our team built Loopy, a self-discovery app based on Schwartz&apos;s theory of basic human values.</description><pubDate>Sun, 14 Sep 2025 03:22:06 GMT</pubDate><category>Nexters</category><category>Nexters 27th Cohort</category><category>development</category><category>backend</category><category>prompt engineering</category></item><item><title>Solving a Concurrency Problem with a Single UPDATE</title><link>https://pythonstrup.com/blog/7/</link><guid isPermaLink="true">https://pythonstrup.com/blog/7/</guid><description>Suppose we are designing a first-come, first-served event system. The requirements are listed below. If 1,000 people request 100 available items at the same time, how can we ensure that exactly 100 people receive one? The solutions commonly proposed in this situation are listed below.</description><pubDate>Wed, 13 Aug 2025 13:40:09 GMT</pubDate><category>java</category><category>MySQL</category><category>redis</category><category>Spring</category><category>optimistic locking</category><category>concurrency</category><category>concurrency control</category><category>exclusive lock</category><category>distributed lock</category><category>pessimistic locking</category></item><item><title>Solving Distributed Cache Synchronization with Redis Pub/Sub</title><link>https://pythonstrup.com/blog/6/</link><guid isPermaLink="true">https://pythonstrup.com/blog/6/</guid><description>Our team began a project integrating with an external system. The requirement seemed simple: &quot;We need to use an external API to determine whether an order can be placed on a given date.&quot; In practice, however, giving customers accurate information required fetching 40–60 date-specific delivery plans at once on a single screen. Even with parallel processing…</description><pubDate>Sat, 09 Aug 2025 10:55:20 GMT</pubDate><category>java</category><category>pub/sub</category><category>redis</category><category>Spring</category><category>Local Cache</category><category>Cache Hierarchy</category></item><item><title>Why Removing @Transactional Doubled Performance in Production</title><link>https://pythonstrup.com/blog/5/</link><guid isPermaLink="true">https://pythonstrup.com/blog/5/</guid><description>In Spring, @Transactional(readOnly = true) is commonly said to optimize performance by changing dirty checking to Manual mode. In practice, however, unnecessary JDBC calls can actually make it slower. Based on real call traces from Elastic APM, this post analyzes how read-only transactions affect performance and suggests a more practical alternative.</description><pubDate>Thu, 08 May 2025 13:38:02 GMT</pubDate><category>@Transactional</category><category>jdbc</category><category>JPA</category><category>MySQL</category><category>set_option</category><category>Spring</category></item><item><title>My Final Geultto</title><link>https://pythonstrup.com/blog/4/</link><guid isPermaLink="true">https://pythonstrup.com/blog/4/</guid><description>I liked the person I was becoming: part of a community, connecting with others, writing, and growing. That was why I joined Cohort 10 as well. As I began my final Geultto cohort, I set several goals. Unlike during Cohort 9, I was no longer working overtime every day, so I thought I would have more room to enjoy the experience this time.</description><pubDate>Sun, 30 Mar 2025 06:14:21 GMT</pubDate><category>Developer</category><category>Geultto Cohort 10</category><category>Final Geultto</category><category>Blog</category></item><item><title>Is Your Memory Healthy?</title><link>https://pythonstrup.com/blog/3/</link><guid isPermaLink="true">https://pythonstrup.com/blog/3/</guid><description>Have you ever seen a system that appeared perfectly healthy in production suddenly slow down, take longer to respond, and eventually fail? Did you know that a single line of code we commonly overlook can degrade application performance and even cause a server outage? Problems like these usually begin with a small memory-management mistake…</description><pubDate>Sun, 16 Mar 2025 08:55:50 GMT</pubDate><category>java</category><category>memory</category><category>Spring</category><category>Memory Leak</category></item><item><title>Between Technology and Management: My Nexters Cohort 26 Retrospective</title><link>https://pythonstrup.com/blog/2/</link><guid isPermaLink="true">https://pythonstrup.com/blog/2/</guid><description>I did not even know how Nexters operated, yet I boldly submitted an idea. Taking on the PM role would give me countless details to manage, but I believed that pushing myself through a genuinely difficult experience would help me grow. I wanted to become the center of collaboration and gain experience leading a team and solving problems. Rather than simply completing my assigned work…</description><pubDate>Sun, 02 Mar 2025 05:04:47 GMT</pubDate><category>Nexters</category><category>PM</category><category>Developer</category><category>Nexters Cohort 26</category></item><item><title>2024 Retrospective</title><link>https://pythonstrup.com/blog/1/</link><guid isPermaLink="true">https://pythonstrup.com/blog/1/</guid><description>Once again, I successfully maintained my one-commit-a-day streak throughout the year. It no longer feels like, &quot;I develop because I have to make one commit a day.&quot; Instead, it feels more like, &quot;I develop every day, and one commit a day naturally records that process.&quot; It is almost like keeping a diary for development. I see this as a clearly positive change. My experience in Geultto Cohort 9…</description><pubDate>Sun, 02 Feb 2025 05:50:03 GMT</pubDate><category>Developer</category><category>Retrospective</category></item></channel></rss>