6.7 KiB
UI Performance Optimization Analysis: Replace Meteor.call with Pub/Sub
Current Issues Identified
The codebase uses several patterns where Meteor.call() could be replaced with pub/sub subscriptions for faster UI updates:
CRITICAL OPPORTUNITIES (High Impact)
1. cron.getMigrationProgress - Polling Every 2 Seconds
Location: imports/cronMigrationClient.js lines 26-53, called every 2 seconds via setInterval
Current Issue:
- Polls for progress data every 2000ms even when nothing is changing
- Adds server load with repeated RPC calls
- Client must wait for response before updating
Recommended Solution:
- Already partially implemented! Migration status is published via
cronMigrationStatuspublication - Keep existing pub/sub for status updates (statusMessage, status field)
- Still use polling for
getMigrationProgress()for non-status data (migration steps list, ETA calculation)
Implementation Status: ✅ Already in place
2. AccountSettings Helper Methods - Used in Profile Popup
Location: client/components/users/userHeader.js lines 173, 182, 191
Current Methods:
Meteor.call('AccountSettings.allowEmailChange', (_, result) => {...})
Meteor.call('AccountSettings.allowUserNameChange', (_, result) => {...})
Meteor.call('AccountSettings.allowUserDelete', (_, result) => {...})
Current Issue:
- Callbacks don't return values (templates can't use reactive helpers with Meteor.call callbacks)
- Requires separate async calls for each setting
- Falls back to unresponsive UI
Recommended Solution:
- Use existing
accountSettingspublication (already exists inserver/publications/accountSettings.js) - Create reactive helpers that read from
AccountSettingscollection instead - Subscribe to
accountSettingsin userHeader template
Benefits:
- Instant rendering with cached data
- Reactive updates if settings change
- No network round-trip for initial render
- Saves 3 Meteor.call() per profile popup load
3. cron.getJobs - Polling Every 2 Seconds
Location: imports/cronMigrationClient.js line 62-67, called every 2 seconds
Current Issue:
- Fetches list of all cron jobs every 2 seconds
- RPC overhead even when jobs list hasn't changed
Recommended Solution:
- Create
cronJobspublication inserver/publications/cronJobs.js - Publish
CronJobStatus.find({})for admin users - Subscribe on client, use collection directly instead of polling
Benefits:
- Real-time updates via DDP instead of polling
- Reduced server load
- Lower latency for job status changes
4. toggleGreyIcons, setAvatarUrl - User Preference Updates
Location: client/components/users/userHeader.js lines 103, 223
Current Pattern:
Meteor.call('toggleGreyIcons', (err) => {...})
Meteor.call('setAvatarUrl', avatarUrl, (err) => {...})
Recommended Solution:
- These are write operations (correct for Meteor.call)
- Keep Meteor.call but ensure subscribed data reflects changes immediately
- Current user subscription should update reactively after call completes
Status: ✅ Already correct pattern
5. setBoardView, setListCollapsedState, setSwimlaneCollapsedState
Location: client/lib/utils.js lines 293, 379, 420
Current Pattern: Write operations via Meteor.call
Status: ✅ Already correct pattern (mutations should use Meteor.call)
MODERATE OPPORTUNITIES (Medium Impact)
6. getCustomUI, getMatomoConf - Configuration Data
Location: client/lib/utils.js lines 748, 799
Current Issue:
- Fetches config data that rarely changes
- Every template that needs it makes a separate call
Recommended Solution:
- Create
customUIandmatomoConfigpublications - Cache on client, subscribe once globally
- Much faster for repeated access
7. Attachment Migration Status - Multiple Calls
Location: client/lib/attachmentMigrationManager.js lines 66, 142, 169
Methods:
attachmentMigration.isBoardMigratedattachmentMigration.migrateBoardAttachmentsattachmentMigration.getProgress
Recommended Solution:
- Create
attachmentMigrationStatuspublication - Publish board migration status for boards user has access to
- Subscribe to get migration state reactively
8. Position History Tracking - Fire-and-Forget Operations
Location: client/lib/originalPositionHelpers.js lines 12, 26, 40, 54, 71
Methods:
positionHistory.trackSwimlanepositionHistory.trackListpositionHistory.trackCard- Undo/redo methods
Current: These are write operations Status: ✅ Correct to use Meteor.call (not candidates for pub/sub)
ALREADY OPTIMIZED ✅
These are already using pub/sub properly:
Meteor.subscribe('setting')- Global settingsMeteor.subscribe('board', boardId)- Board dataMeteor.subscribe('notificationActivities')- NotificationsMeteor.subscribe('sessionData')- User session dataMeteor.subscribe('my-avatars')- User avatarsMeteor.subscribe('userGreyIcons')- User preferencesMeteor.subscribe('accountSettings')- Account settingsMeteor.subscribe('cronMigrationStatus')- Migration status (just implemented)
IMPLEMENTATION PRIORITY
Priority 1 (Quick Wins - 30 mins)
- Fix AccountSettings helpers - Use published data instead of Meteor.call
- Replace callbacks in templates with reactive collection access
- Already subscribed, just need to use it
Priority 2 (Medium Effort - 1 hour)
- Add cronJobs publication - Replace polling with pub/sub
- Add customUI publication - Cache config data
- Add matomoConfig publication - Cache config data
Priority 3 (Larger Effort - 2 hours)
- Add attachmentMigrationStatus publication - Multiple methods become reactive
- Optimize cron.getMigrationProgress - Further reduce polling if needed
PERMISSION PRESERVATION
All recommended changes maintain existing permission model:
- accountSettings: Already published to all users
- cronJobs/cronMigrationStatus: Publish only to admin users (check in publication)
- attachmentMigrationStatus: Publish only to boards user is member of
- customUI/matomoConfig: Publish to all users (public config)
No security changes needed - just move from Meteor.call to pub/sub with same permission checks.
PERFORMANCE IMPACT ESTIMATION
Current State (with polling)
- 1 poll call every 2 seconds = 30 calls/minute per client
- 10 admin clients = 300 calls/minute to server
- High DDP message traffic
After Optimization
- 1 subscription = 1 initial sync + reactive updates only
- 10 admin clients = 10 subscriptions total
- 90% reduction in RPC overhead
- Sub-100ms updates instead of up to 2000ms latency