feat: integrate RealtimeManager into constructive preset and cache lifecycle#1119
Merged
pyramation merged 9 commits intomainfrom May 11, 2026
Merged
feat: integrate RealtimeManager into constructive preset and cache lifecycle#1119pyramation merged 9 commits intomainfrom
pyramation merged 9 commits intomainfrom
Conversation
…fecycle - Add enableRealtime flag to ConstructivePresetOptions (default: false) - Add enableRealtime to DatabaseSettings and database_settings SQL query - Conditionally include RealtimeSubscriptionsPreset when enableRealtime is true - Extend GraphileCacheEntry with optional realtimeManager field - Create and start RealtimeManager in createGraphileInstance when enabled - Stop RealtimeManager in disposeEntry on cache eviction - Wire enableRealtime + pool from server middleware to createGraphileInstance - Extract PgSubscriber from resolved preset for cursor event dispatch
Contributor
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
This comment has been minimized.
This comment has been minimized.
The enable_realtime column doesn't exist yet in services_public.database_settings or services_public.api_settings. Referencing it causes the entire query to fail, which silently drops ALL feature flags (caught by try/catch returning undefined). This broke the Bob restricted API test because enablePresignedUploads fell back to the default (true) instead of the api_settings override (false). Default enableRealtime to false in toDatabaseSettings until the migration in constructive-db adds the column.
Now that constructive-db#1105 adds the enable_realtime column to both services_public.database_settings and services_public.api_settings, restore the SQL query to read it via the standard COALESCE cascade (api_settings override → database_settings default). Removes the temporary hardcoded enableRealtime: false fallback.
This comment has been minimized.
This comment has been minimized.
…tions
All 5 settings query functions (queryRlsSettings, queryCorsSettings,
queryPubkeySettings, queryWebauthnSettings, queryDatabaseSettings)
previously used bare catch { return undefined } which silently
swallowed SQL errors — including schema mismatches like missing columns.
Now each catch logs with log.warn including the function name and error
message, making query failures immediately visible in server logs while
still gracefully degrading to defaults.
…merged The CI database doesn't have the enable_realtime column yet, so the COALESCE query fails. Keep the hardcoded enableRealtime: false for now; the SQL wiring will be a follow-up commit once the DB migration lands. The log.warn fixes for silent catch blocks are retained.
Remove the WithPgClient/PgClient callback abstraction. CursorTracker and RealtimeManager now accept a Queryable (typically pg.Pool) directly and call pool.query() for one-shot queries — the same pattern api.ts uses. This removes connection-management logic from graphile-cache (where it didn't belong) and eliminates an unnecessary abstraction layer.
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.
Summary
Wires the
RealtimeManager(fromgraphile-realtime-subscriptions, merged in #1111) into the PostGraphile preset system and cache lifecycle, gated behind a per-tenantenableRealtimedatabase feature flag (default:false).Changes across 4 layers:
Feature flag — Adds
enableRealtime?: booleantoConstructivePresetOptions(defaultfalse) andDatabaseSettings, following the existing pattern forenableAggregates,enableLlm, etc.Preset — When
enableRealtimeis true,RealtimeSubscriptionsPreset()is included increateConstructivePreset, which adds per-table subscription fields for@realtime-tagged tables.Cache lifecycle —
GraphileCacheEntrygains an optionalrealtimeManagerfield.createGraphileInstancecreates and starts aRealtimeManagerwhen enabled;disposeEntrystops the manager on cache eviction. BothpgSubscriberand the pg pool are extracted from the resolved preset'spgServices[0]— no separate pool parameter is needed, since the pool is already embedded bymakePgService({ pool, schemas })(managed bypg-cache).Server middleware —
graphile.tspassesenableRealtimethrough tocreateGraphileInstance.api.tsaddsenableRealtimetoDatabaseSettingsbut hardcodes it tofalsebecauseenable_realtimedoes not yet exist as a column inservices_public.database_settingsorservices_public.api_settings. The column migration is in constructive-db #1105; once merged, a follow-up commit will wire the COALESCE cascade.Error observability — Replaced bare
catch { return undefined; }withcatch (e: any) { log.warn(...); return undefined; }in 5 settings query functions (queryRlsSettings,queryCorsSettings,queryPubkeySettings,queryWebauthnSettings,queryDatabaseSettings). Previously these silently swallowed SQL errors, masking real issues like missing columns or connection failures.Updates since last revision
withPgClientFromPool— CursorTracker/RealtimeManager now usepool.query()directly. The previousWithPgClientcallback abstraction (acquire client → callback → release) was unnecessary since every usage was a single one-shot query — exactly whatpool.query()does internally. Replaced theWithPgClient/PgClienttypes with a singleQueryableinterface ({ query() }), andcreate-instance.tsnow passes the pool straight toRealtimeManagerwith no wrapper. This removes connection-management logic from graphile-cache where it didn't belong.createGraphileInstancepreviously accepted an optionalpoolfromgraphile.ts, duplicating pool management thatpg-cachealready handles. The pool is now extracted fromresolvedPreset.pgServices[0].adaptorSettings.pool— the same instance threaded into the preset bymakePgService({ pool, schemas }). This makespg-cachethe single source of truth for pool lifecycle.log.warn; removed prematureenable_realtimecolumn references fromDATABASE_SETTINGS_SQL.Review & Testing Checklist for Human
(resolvedPreset as any).pgServices?.[0]increate-instance.ts— Accesses PostGraphile v5 internals viaas any. Confirm the resolved preset actually exposespgSubscriberandadaptorSettings.poolon the first pg service at this point in the lifecycle (afterserv.ready()). A null subscriber or null pool logs a warning and skips gracefully.pgService?.adaptorSettings?.pool— This relies on@dataplan/pg'smakePgServicestoring the pool at this path. Verify that the pool object returned here satisfies theQueryableinterface (i.e. has a.query(text, values)method). Since it's apg.Pool, it should, but confirm this is stable across PostGraphile v5 releases.log.warnnoise level — The 5 catch blocks now log atwarnlevel. Verify that in normal production operation (where modules likerls_moduleorwebauthn_modulemay not be deployed for every tenant) these queries don't fail routinely. If they do, some should uselog.debuginstead (likequeryAuthSettingsalready does). The intent is that these core settings tables always exist, so a SQL error here is genuinely unexpected.schema: 'realtime_public'increate-instance.ts— Verify this is correct for all tenant configurations, or whether it should be derived from the preset/settings.enableRealtimeis permanentlyfalseuntil constructive-db #1105 is merged, theenable_realtimecolumn exists, andapi.tsSQL is updated to include the COALESCE column.Suggested test plan: Deploy to a test environment, verify existing feature-flag gating still works (e.g. presigned uploads enabled/disabled per API), then enable
enableRealtimemanually in code to confirmRealtimeManagerstarts and connects toPgSubscriber.Notes
RealtimeManageris dynamically imported and wrapped in try/catch, so if the import fails the PostGraphile instance still works — realtime just won't be active.createGraphileInstanceis unaffected sinceenableRealtimeis optional with a safe default.Link to Devin session: https://app.devin.ai/sessions/19485cf5cc58416a9f86068563d512f5
Requested by: @pyramation