0%

1. Background

ThreadLocal provides thread-local variables. Because each thread has its own isolated copy, ThreadLocal is commonly used to store thread-specific information like logged-in user details or database connection config. But there’s a catch most people miss: ThreadLocal only works in synchronous threads. It doesn’t carry over to async threads or thread pools. This post explores how to propagate ThreadLocal context across async boundaries.

Read more »


I’ve been swamped with work and life lately — both have been chaotic, and the blog went on hiatus. Should I write about tech or food? Food, of course.

Today I’m making radish balls. While I was cooking and tasting, I suddenly remembered a day back in eighth grade when we pooled our money to buy five jin of radish balls and sneaked them during English class. Fifteen years later, the memory is still vivid.

Read more »


Since domestic pork became scarce and expensive, imported pork has been the default at most markets. Foreign farms don’t castrate their piglets the way Chinese farms do, so the meat tends to be gamey and strong-tasting. Today I picked up some pork with low expectations and left a note on the Dingdong delivery app: “Chinese pork only!”

Today’s recipe: Lion’s Head meatballs.

Read more »

1. Background

In our payment system, thread pools play a critical role in batch payment processing. As transaction volume grew, the payment endpoint’s throughput degraded to the point where a single batch could take over 5 minutes — unacceptable for the calling services. The obvious fix is to increase the thread count and queue capacity, but figuring out the right numbers without over-provisioning is hard to do by feel alone. Prometheus + Grafana is a well-established monitoring stack, and it works well for thread pool observability too.

Read more »

1. Background

I was working on an online account adjustment system this week, and one requirement was tricky: after submitting an adjustment request, the system records the corresponding adjustment types in a database table. On the review page, the filter for adjustment types needed to support multi-select. Here’s the enum:

1
2
3
4
5
6
7
8
9
10
11
12
public enum AdjustTypeEnum {
/**
* Adjustment type enum; a single request may involve multiple types,
* stored as comma-separated values in the database.
*/
FINE(0, "Expected Penalty Interest"),
TOTAL_REPAYMENT(1, "Expected Total Repayment"),
FACT_REPAYMENT(2, "Actual Total Repayment"),
FACT_PAYMENT_DATE(3, "Actual Payment Date"),
OVERDUE_DAYS(4, "Overdue Days"),
PAYMENT_STATUS(5, "Repayment Status");
}

If request A involves both “Expected Penalty Interest” and “Expected Total Repayment,” the stored value would be 0,1. On the review page, if the filter includes either of those two types, the query should return this request. The problem is that MySQL’s FIND_IN_SET only supports single-value matching — it can’t flexibly decompose the stored comma-separated values against a multi-select filter. This meant rethinking both the storage format and the query logic.

Read more »

1. Background

Plenty of messaging systems implement publish-subscribe — Kafka, RabbitMQ, ActiveMQ are the big names. Lighter options include Guava’s EventBus and Redis pub/sub. The MQ heavyweights get plenty of coverage elsewhere, so this post focuses on how Redis handles pub/sub under the hood. In production, Redis pub/sub sees limited adoption for two reasons. First, delivery guarantees are weak: if the network drops, in-flight messages are gone with no recovery. Second, Redis runs pub/sub through a single-threaded event loop, so a message burst can bloat the output buffer and even crash the server. That said, when data safety isn’t critical, Redis pub/sub is hard to beat for simplicity.

Read more »



I was craving my mom’s youmo today, what most people call scallion pancakes. My rental place doesn’t have the best kitchen setup, but I figured I’d give it a shot anyway.


Read more »