6 - API (refactor): Remove Global State#231
Open
RobertRosca wants to merge 14 commits into
Open
Conversation
RobertRosca
force-pushed
the
feat/improved-api-errors
branch
from
July 10, 2026 14:13
ea9ed06 to
4ca4f6e
Compare
RobertRosca
force-pushed
the
refactor/remove-global-state
branch
2 times, most recently
from
July 10, 2026 14:20
141c8aa to
c90b2c7
Compare
Member
|
Hmm, when I checked Also we still seem to use |
RobertRosca
force-pushed
the
feat/improved-api-errors
branch
from
July 17, 2026 06:20
02a5f78 to
c60b40f
Compare
RobertRosca
force-pushed
the
refactor/remove-global-state
branch
from
July 17, 2026 06:20
c90b2c7 to
afef36c
Compare
RobertRosca
force-pushed
the
feat/improved-api-errors
branch
from
July 17, 2026 06:21
c60b40f to
c80d085
Compare
RobertRosca
force-pushed
the
refactor/remove-global-state
branch
from
July 17, 2026 06:21
afef36c to
102d22a
Compare
RobertRosca
force-pushed
the
feat/improved-api-errors
branch
from
July 17, 2026 08:40
c80d085 to
0ddd29c
Compare
RobertRosca
force-pushed
the
refactor/remove-global-state
branch
from
July 17, 2026 08:40
102d22a to
3dfd6d2
Compare
RobertRosca
force-pushed
the
feat/improved-api-errors
branch
from
July 17, 2026 09:09
0ddd29c to
c9d9daf
Compare
RobertRosca
force-pushed
the
refactor/remove-global-state
branch
from
July 17, 2026 09:09
3dfd6d2 to
0873ce9
Compare
RobertRosca
force-pushed
the
feat/improved-api-errors
branch
from
July 17, 2026 09:11
c9d9daf to
4c5700c
Compare
RobertRosca
force-pushed
the
refactor/remove-global-state
branch
from
July 17, 2026 09:11
0873ce9 to
dd5d976
Compare
RobertRosca
force-pushed
the
feat/improved-api-errors
branch
from
July 17, 2026 09:12
4c5700c to
bf4af8b
Compare
RobertRosca
force-pushed
the
refactor/remove-global-state
branch
2 times, most recently
from
July 17, 2026 09:12
1d7fdf0 to
bd160c7
Compare
RobertRosca
force-pushed
the
feat/improved-api-errors
branch
from
July 17, 2026 09:12
bf4af8b to
bce3ee7
Compare
RobertRosca
force-pushed
the
refactor/remove-global-state
branch
from
July 17, 2026 10:46
bd160c7 to
15f9109
Compare
RobertRosca
force-pushed
the
feat/improved-api-errors
branch
2 times, most recently
from
July 17, 2026 11:01
04f2042 to
951da6d
Compare
RobertRosca
force-pushed
the
refactor/remove-global-state
branch
2 times, most recently
from
July 20, 2026 09:26
5c8c396 to
5db7605
Compare
RobertRosca
force-pushed
the
feat/improved-api-errors
branch
2 times, most recently
from
July 20, 2026 09:28
08d0c88 to
349cfa2
Compare
RobertRosca
force-pushed
the
refactor/remove-global-state
branch
from
July 20, 2026 09:28
5db7605 to
4b537a3
Compare
RobertRosca
force-pushed
the
refactor/remove-global-state
branch
from
July 20, 2026 09:30
4b537a3 to
1d8be88
Compare
RobertRosca
marked this pull request as ready for review
July 20, 2026 09:35
Member
|
The question about Also on the |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR no. 6 of the big refactor.
This PR gets rid of the module-level singletons that the app bootstrapped at startup (
_db.__ENGINE,_mymdc.CLIENT,auth.__CLIENT,TOKEN_STORE, registry metaclass, etc...) and replaces them with a single frozenAppStatethat's built once in the lifespan and handed out via DI. Also adds ADR-002 and ADR-003 which cover the reasoning.Details
Previously any function could reach any dependency by importing a global, which is easy/short to write but has a bunch of downsides: init order is critical and pretty opaque, tests have to mutate/clear process-wide state between cases, you can't have two differently-configured apps in one process, in-process state looks shareable but silently breaks under multiple workers, etc...
ADR-002 goes through this and decides on a single typed
AppStatecontainer built in the lifespan with dependencies injected everywhere else, so init is typed and order-explicit (defined by constructor) and tests inject fakes by building state instead of patching modules.AppState + factories
state.pyholds a frozenAppStatedataclass and thecreate_*factory functions. The factories are pure - they takeSettings(or already-built collaborators) and construct their object, no module state/side effects.AppStatecurrently has:db_engine/db_sessionmakermymdc_clientoauth_client(Nonewhen auth is disabled)token_storedamnit_registrysubscription_cursorsThe lifespan builds all of these and attaches the result to
app.state, slices can get it via aget_app_stateFastAPI dependency.Along the way this also:
TOKEN_STOREdict for aTokenStore(InMemoryTokenStore)Registrymetaclass with a plainDamnitDBRegistryAppStateget_connection)Settings
ADR-003 covers the way that settings are injected and is included here too since it is part of the global state that I wanted to remove, but (again) a bit of a lie since the actual removal of the
settings = Settings()singleton isn't in this branch andcreate_app()still imports the global for now. The actual implementation of this is in a later branch.Tests
test_state.pycovers theAppStateDI surface, factories, and stores.conftest.pys now build anAppStatewith fakes (mock MyMdC client, in-memory token store) instead of monkeypatching modules and clearing caches between tests 🎉