Skip to content
All writing Part 02 of 04 · Thread-Safe Login, the Hard Way
Engineering · 1 min read

Finish First, Then Publish: Never Ship a Half-Built Object

Build shared state locally, confirm success, then assign it last in one write. This pattern avoids exposing half-initialized objects to other threads.

Finish First, Then Publish: Assign Shared State Only After Success

When a synchronization primitive only provides isolation, not rollback, atomicity has to be built manually. The rule fits in one sentence: defer assignment to the shared field until last.

It’s just three steps:

  1. Do the work into a local variable.
  2. Confirm it succeeded.
  3. Only then assign it to the shared variable, last, in a single write.

Never publish an object that’s only half-initialized: another thread might read that half-finished state. This is “safe publication”: a reference should only become visible once the object is fully constructed.

session = requests.Session()          # build in a local variable
resp = session.post(LOGIN_URL, ...)   # succeed first
resp.raise_for_status()
self.session = session                # publish only after success, single write

If post() throws, no shared state has been touched, so the next thread won’t read torn state either.

The pitfall people fall into most in practice is writing the order backwards: putting self.session = requests.Session() up front, then running a login that might fail. If that login throws, the shared field is already pointing at a session that never finished logging in.

Publishing a reference tells other threads “this is done,” so make sure it actually is.


References:

Related: see the mutex vs. ACID isolation breakdown, how with lock: guarantees release on exception, or go back to the four-lesson overview on making login thread-safe.

Tags #concurrency #python
// connect

Be brave | Be wise | Be grateful

21 BreakinCode

// elsewhere
LinkedInMedium (lang: en)Life RecordYoutube
wh:~$William Hung· © 2026 Taipei · GMT+8 · Available for collaboration