Skip to content

fix: synchronous table startup for ETS/DETS/Counter adapters#44

Merged
MikaAK merged 1 commit into
mainfrom
fix/synchronous-table-startup
Apr 27, 2026
Merged

fix: synchronous table startup for ETS/DETS/Counter adapters#44
MikaAK merged 1 commit into
mainfrom
fix/synchronous-table-startup

Conversation

@MikaAK
Copy link
Copy Markdown
Owner

@MikaAK MikaAK commented Apr 27, 2026

Summary

  • Cache.ETS, Cache.DETS, and Cache.Counter all wrapped their setup in Task.start_link(fn -> ... end). The task spawned, start_link returned {:ok, pid}, and the supervisor moved on — but the table creation/opening was still running inside the task. Callers that hit the cache immediately after the supervisor came up could see a missing table.
  • Each adapter's task now sends a :ready signal back to the parent after setup completes; start_link blocks on that signal (or on {:EXIT, pid, reason} if setup crashes), giving the supervisor a genuinely synchronous start.
  • Cache.PersistentTerm has no setup work, and Cache.RefreshAhead.start_tracker already creates its tracker ETS table before Task.start_link runs — neither has a race, so both were left alone.

Test plan

  • mix test test/cache/ets_test.exs test/cache/dets_test.exs test/cache/counter_test.exs — 85 tests, 0 failures
  • mix credo --strict lib/cache/ets.ex lib/cache/dets.ex lib/cache/counter.ex — no issues
  • Spot-check: a fresh test using start_supervised! followed by an immediate get/put (no Process.sleep) passes against the patched code, confirming the table is ready the moment start_link returns.

Follow-up (not in this PR)

The Process.sleep(100) calls scattered across the existing ETS/DETS/Counter tests are now unnecessary and can be removed in a follow-up cleanup.

…eturns

Cache.ETS, Cache.DETS, and Cache.Counter all used Task.start_link to
spawn a hibernating owner process, but the table setup ran inside the
task. start_link returned as soon as the task was spawned, so the
supervisor considered the child started before the table actually
existed — callers that touched the cache immediately after the
supervisor came up could hit a missing table.

Each adapter's task now sends a :ready signal back to the parent after
setup, and start_link blocks on that signal (or on {:EXIT, pid, reason}
if setup crashes). The supervisor sees a genuinely synchronous start.

Cache.PersistentTerm has no setup and Cache.RefreshAhead.start_tracker
already creates its table before Task.start_link, so neither needs the
handshake.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 27, 2026

Codecov Report

❌ Patch coverage is 91.11111% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.46%. Comparing base (ff1c3df) to head (1c24b72).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
lib/cache/ets.ex 88.23% 2 Missing ⚠️
lib/cache/counter.ex 92.85% 1 Missing ⚠️
lib/cache/dets.ex 92.85% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #44      +/-   ##
==========================================
- Coverage   83.46%   83.46%   -0.01%     
==========================================
  Files          22       22              
  Lines         617      635      +18     
==========================================
+ Hits          515      530      +15     
- Misses        102      105       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@MikaAK MikaAK merged commit b75fa2b into main Apr 27, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant