Skip to content

Performance refactor#362

Open
edwardhorsford wants to merge 5 commits into
mainfrom
performance-refactor
Open

Performance refactor#362
edwardhorsford wants to merge 5 commits into
mainfrom
performance-refactor

Conversation

@edwardhorsford

Copy link
Copy Markdown
Contributor

What

Stops copying the whole generated dataset (~4.5MB) into every session, which
was pushing Heroku past its 512MB memory quota.

Seed data (participants, clinics, events) now lives in a shared read-only
store (app/lib/data-store.js), loaded once at boot and attached to each
request by middleware. Sessions only store changed records (data._changes,
whole records keyed by id), overlaid onto the shared arrays per request —
so routes and views read data.events etc exactly as before.

Details

  • Serialised session size: ~4.5MB → ~40KB
  • RSS under load roughly halves, and extra sessions are now near-free
  • Temp working copies (data.event, data.participant) are deep clones;
    all writes funnel through the update helpers
  • Shared data is deep-frozen in development to catch accidental mutation
    (escape hatch: freezeSharedData: false in config)
  • Changes are stamped with a generation id, so a regenerate or profile swap
    resets data for every session — swap-and-demo keeps working as expected
  • Seed data is generated at build time on Heroku (heroku-postbuild)
  • New docs/data-conventions.md covers reading vs updating data

Notes for reviewers

  • Reading data needs no new knowledge; only writes have conventions
  • Verified locally: full screening flow, reading (opinions, defer, priors),
    participant edit, regenerate, two concurrent sessions
  • Not yet verified on Heroku — memory comparison to follow after deploy

Clinics now live in a boot-time shared store (deep-frozen in dev) and are
attached to each request by middleware; a toJSON override keeps them out
of the serialised session. First collection of three - participants and
events follow once the write path is funnelled through helpers.
Prepares for serving events and participants from the shared store:

- Temp working copies (data.event, data.participant) are now deep clones,
  so form merges can never write into the source records
- Priors, deferral and reading writes build replacement records and save
  via updateEventData instead of mutating found records in place
- Session-copied seed arrays are deep-frozen in development (config
  escape hatch: freezeSharedData) so leftover in-place writers throw
…s only

Sessions now persist only changed records (data._changes, whole records
keyed by id, stamped with the data generation they were made against).
Middleware overlays them onto the shared store's arrays each request, so
routes and views read data.events etc unchanged.

- Update helpers write changes to _changes as well as the attached array
- generationInfo comes from the store, so a regenerate or profile swap
  by one session resets data for every session (stale stamps discarded)
- Daily regeneration check now reads the store, not the session
- Serialised session size drops from ~4.5MB to ~40KB; RSS under a
   200-request two-session load roughly halves
- New docs/data-conventions.md explains reading vs updating data
npm run generate writes the seed files ahead of boot; heroku-postbuild
calls it so dynos start with data on disk. Daily staleness check at
runtime is unchanged (dyno cycling keeps dates fresh).
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