Platform
Cron Management

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:

JobScheduleCron ExpressionDescription
Facilities/Regions SyncWeekly Monday 2:00 AM EST / 7:00 AM UTC0 7 * * 1Syncs facility and region data from MySQL to Supabase
Members SyncDaily 2:15 AM EST / 7:15 AM UTC15 7 * * *Syncs member records from MySQL to Supabase
Positions SyncDaily 2:45 AM EST / 7:45 AM UTC45 7 * * *Syncs member position assignments
Intercom SyncDaily 3:00 AM EST / 8:00 AM UTC0 8 * * *Syncs Active/Retired members to Intercom

Execution Details:

  • Jobs run automatically when the server starts
  • Execution uses setImmediate for 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:

  1. Navigate to /cron and log in
  2. View all jobs with current status
  3. Check next scheduled run times
  4. Monitor last execution duration

Manually Trigger a Job:

  1. Locate the job you want to run
  2. Click the "Trigger" button
  3. Wait for execution to complete
  4. Verify status changes to "idle" when done
  5. Check logs for any errors

Monitor Job History:

  1. View "Last Run" timestamp for each job
  2. Check "Duration" to identify performance issues
  3. Review error messages for failed jobs
  4. 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 running
  • setCompleted(jobName, duration) - Mark job as completed
  • setError(jobName, error) - Mark job as failed
  • getStatus(jobName) - Get current job status
  • getAllStatuses() - Get all job statuses
  • triggerJob(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 dev

Filter 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 error

Common Issues

Job Not Running on Schedule

Symptoms: Job shows old "Last Run" timestamp, "Next Run" in the past

Solutions:

  1. Verify server is running: doctl apps list
  2. Check server logs for cron initialization
  3. Restart server if needed
  4. Manually trigger job via UI to verify it works

Job Stuck in "Running" State

Symptoms: Job status shows "running" for extended period

Solutions:

  1. Check application logs for errors or timeouts
  2. Verify database connections (MySQL and Supabase)
  3. Restart server to reset job state
  4. Check for long-running database queries

Job Fails with Error

Symptoms: Job status shows "error", error message displayed

Solutions:

  1. Read error message in UI for specific issue
  2. Check database connectivity
  3. Verify environment variables are set
  4. Review application logs for stack trace
  5. Manually test sync command: npm run sync:members

Manual Trigger Not Working

Symptoms: Clicking "Trigger" has no effect

Solutions:

  1. Verify Auth0 session is valid (try logging out/in)
  2. Check browser console for JavaScript errors
  3. Verify server is responding: curl https://platform.natca.org/api/health
  4. 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 automatically

2. 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:intercom

Development 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 handling

Migration 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.js code
  • 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 components

Security Considerations

Authentication

Session Protection:

  • All /cron endpoints 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


The in-app cron system provides cost-effective, reliable scheduling for MyNATCA platform data synchronization with simplified management and real-time monitoring capabilities.