Cron Management
The MyNATCA Platform uses in-app cron scheduling (node-cron) for automated data synchronization tasks. This provides cost-effective, simplified management with real-time monitoring capabilities.
Overview
Benefits of In-App Cron:
- Cost Savings: Eliminates need for external job components ($5/month per job on DigitalOcean)
- Simplified Deployment: No separate job configuration required
- Real-Time Monitoring: Web UI for instant status visibility
- Manual Triggers: On-demand job execution via UI or API
- Centralized Logging: All job execution logs in main application server
Scheduled Jobs
The platform runs four automated sync jobs with the following schedules:
| Job | Schedule | Cron Expression | Description |
|---|---|---|---|
| Facilities/Regions Sync | Weekly Monday 2:00 AM EST / 7:00 AM UTC | 0 7 * * 1 | Syncs facility and region data from MySQL to Supabase |
| Members Sync | Daily 2:15 AM EST / 7:15 AM UTC | 15 7 * * * | Syncs member records from MySQL to Supabase |
| Positions Sync | Daily 2:45 AM EST / 7:45 AM UTC | 45 7 * * * | Syncs member position assignments |
| Intercom Sync | Daily 3:00 AM EST / 8:00 AM UTC | 0 8 * * * | Syncs Active/Retired members to Intercom |
Execution Details:
- Jobs run automatically when the server starts
- Execution uses
setImmediatefor async processing - Status tracking via singleton CronManager
- No external cron daemon required
Cron Management UI
Accessing the Interface
Navigate to the cron management interface at:
- Production:
https://platform.natca.org/cron - Local Development:
http://localhost:1300/cron
Authentication: Requires Auth0 login with valid session
Interface Features
The cron management UI provides:
1. Real-Time Job Status
- Idle: Job waiting for next scheduled run
- Running: Job currently executing
- Error: Job encountered an error on last run
2. Job Metadata
- Last Run: Timestamp of most recent execution
- Next Run: Timestamp of next scheduled execution
- Duration: Execution time of last run (in seconds)
- Error Message: Details of last error (if any)
3. Manual Triggers
- Click "Trigger" button to run any job on-demand
- Job executes asynchronously
- Status updates in real-time
- Page auto-refreshes every 30 seconds
4. Visual Design
- Matches platform theme (NATCA branding)
- Responsive layout
- Color-coded status indicators
- Accessible button controls
Using the Interface
View Job Status:
- Navigate to
/cronand log in - View all jobs with current status
- Check next scheduled run times
- Monitor last execution duration
Manually Trigger a Job:
- Locate the job you want to run
- Click the "Trigger" button
- Wait for execution to complete
- Verify status changes to "idle" when done
- Check logs for any errors
Monitor Job History:
- View "Last Run" timestamp for each job
- Check "Duration" to identify performance issues
- Review error messages for failed jobs
- Use timestamps to correlate with application logs
Architecture
CronManager Singleton
The platform uses a singleton CronManager class (lib/cronManager.js) to track job status:
// Job status structure
{
status: 'idle' | 'running' | 'error',
lastRun: Date | null,
nextRun: Date | null,
duration: number | null,
error: string | null
}Key Methods:
setRunning(jobName)- Mark job as runningsetCompleted(jobName, duration)- Mark job as completedsetError(jobName, error)- Mark job as failedgetStatus(jobName)- Get current job statusgetAllStatuses()- Get all job statusestriggerJob(jobName)- Manually execute a job
Server Integration
Cron jobs are initialized in server.js:
const cron = require('node-cron');
const cronManager = require('./lib/cronManager');
// Schedule facilities/regions sync (Weekly Monday 2:00 AM EST)
cron.schedule('0 7 * * 1', async () => {
setImmediate(async () => {
const startTime = Date.now();
cronManager.setRunning('facilities-regions');
try {
await require('./sync/scripts/sync-facilities')();
await require('./sync/scripts/sync-regions')();
cronManager.setCompleted('facilities-regions', Date.now() - startTime);
} catch (error) {
cronManager.setError('facilities-regions', error.message);
}
});
});
// Similar patterns for other jobs...API Endpoints
Routes (routes/cron.js):
GET /cron- Render cron management UI (requires Auth0 session)GET /cron/status- Get all job statuses (JSON API)POST /cron/trigger/:jobName- Manually trigger a job (requires Auth0 session)
Authentication: All endpoints protected by Auth0 session middleware
Monitoring and Troubleshooting
Viewing Logs
Platform Logs:
# DigitalOcean
doctl apps logs <app-id> --component platform --follow
# Docker
docker-compose logs -f platform
# Local
npm run devFilter for Cron Events:
# Search for specific job
doctl apps logs <app-id> --component platform | grep "Members sync"
# Search for errors
doctl apps logs <app-id> --component platform | grep -i errorCommon Issues
Job Not Running on Schedule
Symptoms: Job shows old "Last Run" timestamp, "Next Run" in the past
Solutions:
- Verify server is running:
doctl apps list - Check server logs for cron initialization
- Restart server if needed
- Manually trigger job via UI to verify it works
Job Stuck in "Running" State
Symptoms: Job status shows "running" for extended period
Solutions:
- Check application logs for errors or timeouts
- Verify database connections (MySQL and Supabase)
- Restart server to reset job state
- Check for long-running database queries
Job Fails with Error
Symptoms: Job status shows "error", error message displayed
Solutions:
- Read error message in UI for specific issue
- Check database connectivity
- Verify environment variables are set
- Review application logs for stack trace
- Manually test sync command:
npm run sync:members
Manual Trigger Not Working
Symptoms: Clicking "Trigger" has no effect
Solutions:
- Verify Auth0 session is valid (try logging out/in)
- Check browser console for JavaScript errors
- Verify server is responding:
curl https://platform.natca.org/api/health - Check server logs for 500 errors
Performance Monitoring
Key Metrics:
-
Duration: Track execution time trends
- Members sync: Target < 120 seconds
- Facilities/Regions: Target < 60 seconds
- Positions: Target < 90 seconds
- Intercom: Target < 600 seconds
-
Error Rate: Monitor failed job executions
- Target: < 1% failure rate
- Alert if 3+ consecutive failures
-
Schedule Accuracy: Verify jobs run on time
- Check "Next Run" vs actual execution time
- Investigate delays > 5 minutes
Dashboard Metrics (via OpenSearch):
- cron.jobs.duration (gauge)
- cron.jobs.errors (counter)
- cron.jobs.executions (counter)Local Development
Running Cron Jobs Locally
1. Start Server with Cron Jobs:
npm run dev
# Cron jobs initialize automatically2. Access Cron UI:
Navigate to http://localhost:1300/cron
3. Test Manual Triggers: Click "Trigger" buttons to test job execution
4. Test Individual Syncs:
# Run sync commands directly
npm run sync:members
npm run sync:facilities
npm run sync:regions
npm run sync:positions
npm run sync:intercomDevelopment Tips
1. Adjust Cron Schedules for Testing:
Edit server.js temporarily for faster execution:
// Change from production schedule
cron.schedule('0 7 * * 1', async () => { ... });
// To every minute for testing
cron.schedule('* * * * *', async () => { ... });Remember to revert before committing!
2. Monitor Console Output:
Development mode shows detailed logging:
{
"timestamp": "2025-10-04T12:00:00.000Z",
"level": "info",
"service": "platform",
"message": "Cron job started",
"context": {
"job": "members-sync"
}
}3. Test Error Handling:
Simulate failures by temporarily breaking database connections:
# Set invalid Supabase URL
export SUPABASE_URL=https://invalid.supabase.co
npm run dev
# Trigger job and verify error handlingMigration Notes
From DigitalOcean Job Components
Previous Architecture:
- 4 separate DigitalOcean job components
- $5/month per job = $20/month total
- Manual configuration in DO dashboard
- Separate logs per job component
New Architecture:
- In-app cron using node-cron package
- $0/month additional cost
- Configured in
server.jscode - Centralized logs in platform server
Migration Checklist:
- Remove job components from
.do/app.yaml - Add node-cron package to dependencies
- Create CronManager singleton
- Add cron routes and UI
- Update documentation
- Test all jobs in production
Rollback Procedure:
If issues arise, you can temporarily scale down the platform to prevent cron execution:
# DigitalOcean: Scale to 0 instances in dashboard
# Then re-deploy with old .do/app.yaml containing job componentsSecurity Considerations
Authentication
Session Protection:
- All
/cronendpoints require valid Auth0 session - No service-to-service authentication for cron routes
- Session timeout: 7 days (rolling)
Authorization:
- Any authenticated user can view job status
- Any authenticated user can trigger jobs manually
- Consider implementing role-based access control (RBAC) for triggers
Best Practices
1. Limit Manual Triggers:
- Don't trigger multiple jobs simultaneously
- Wait for completion before re-triggering
- Monitor logs when manually triggering
2. Protect Error Messages:
- Errors may contain sensitive database info
- Only accessible to authenticated users
- Consider sanitizing error messages for production
3. Monitor Access:
- Log all manual trigger attempts
- Alert on unusual trigger patterns
- Review access logs regularly
Related Documentation
- Platform Overview - Core platform architecture
- Logging System - JSON logging and OpenSearch integration
- Intercom Integration - Intercom sync details
- Deployment Guide - Production deployment procedures
The in-app cron system provides cost-effective, reliable scheduling for MyNATCA platform data synchronization with simplified management and real-time monitoring capabilities.