Repository navigation
perf(contacts): serve the contact field list from Redis - #581
Merged
Merged
Conversation
GET /contacts/fields scanned every contact in the project on each request, re-reading the table once per custom field. At millions of contacts the segment builder took a minute to open (#487). The field names are now registered on write: every path that stores Contact.data adds its keys to a per-project sorted set in Redis, so a new field is offered immediately. Coverage and type are measured by a background contact-fields job in a single pass over the project's contacts, which also prunes keys no contact carries any more. The endpoint only reads Redis and queues a scan when the measurements are missing, older than an hour, or lack a field. Write-triggered scans are debounced by 10 seconds and a project is scanned at most every 5 minutes. A field not measured yet reports coverage as null. A stored JSON null no longer counts toward coverage, and a field holding mixed types reports as string. The segment builder loads its options through SWR. Based on the analysis and single-pass query from #490. Co-authored-by: Pau Sanchez <contact@pausanchez.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Description
Closes #487. Replaces #490, whose analysis and single-pass query this builds on.
GET /contacts/fieldsscanned every contact in the project on each request and re-read the table once per custom field, so the segment builder, workflow condition editor and template editor were slow to open on large projects.ContactService.create,update,upsertand the workflow "update contact" step add theContact.datakeys they store to a per-project sorted set in Redis (one Lua call per write). A new field appears in the pickers immediately.contact-fieldsBullMQ job runs one pass over the project's contacts and stores the result. When it finishes, it also removes keys no contact carries any more. A key first written while a scan is running is kept.Behaviour changes
coverage: null. The editor menus and template lint skip it, and the data settings table shows "—".pending: trueand lists only the standard fields plus fields written since. The frontend polls every 3s while pending.string.Type of Change
feat:New feature (MINOR version bump)fix:Bug fix (PATCH version bump)feat!:Breaking change - new feature (MAJOR version bump)fix!:Breaking change - bug fix (MAJOR version bump)docs:Documentation update (no version bump)chore:Maintenance/dependencies (no version bump)refactor:Code refactoring (no version bump)test:Adding tests (no version bump)perf:Performance improvement (PATCH version bump)Testing
ContactFieldService.test.ts(9 tests): coverage and type, a new field offered before it is measured, no scan for known fields, removal of unused keys, a key written during a scan, field deletion, project isolation.Workflows.test.tsnow creates its contact throughContactService, since custom fields are registered by writes. Three test files that mock Redis got adefineCommandstub.tsc --noEmitand ESLint clean for api and web.Checklist
🤖 Generated with Claude Code