small fixes
This commit is contained in:
+260
@@ -0,0 +1,260 @@
|
|||||||
|
# Cron Job Setup for JobifyGarden
|
||||||
|
|
||||||
|
Since your hosting provider doesn't have Supervisor, you'll use cron jobs to handle scheduled tasks and queue processing.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. SSH access to your server
|
||||||
|
2. Access to crontab configuration
|
||||||
|
3. Verify your application path (likely `/home/jobifyg/public_html` or similar)
|
||||||
|
|
||||||
|
## Setup Instructions
|
||||||
|
|
||||||
|
### Step 1: Make Queue Worker Script Executable
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jobifyg/public_html
|
||||||
|
chmod +x queue-worker.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Configure Crontab
|
||||||
|
|
||||||
|
Edit your crontab:
|
||||||
|
```bash
|
||||||
|
crontab -e
|
||||||
|
```
|
||||||
|
|
||||||
|
Add these lines (replace `/home/jobifyg/public_html` with your actual path):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# =============================================================================
|
||||||
|
# JobifyGarden Cron Jobs
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Laravel Scheduler - REQUIRED
|
||||||
|
# Runs every minute to process scheduled commands
|
||||||
|
* * * * * cd /home/jobifyg/public_html && php artisan schedule:run >> /dev/null 2>&1
|
||||||
|
|
||||||
|
# Queue Worker - REQUIRED
|
||||||
|
# Option 1: Using the helper script (recommended)
|
||||||
|
* * * * * /home/jobifyg/public_html/queue-worker.sh
|
||||||
|
|
||||||
|
# Queue Worker - Option 2: Direct command (if script doesn't work)
|
||||||
|
# * * * * * cd /home/jobifyg/public_html && php artisan queue:work --max-time=50 --stop-when-empty --sleep=3 --tries=3 >> storage/logs/queue.log 2>&1
|
||||||
|
|
||||||
|
# Queue Restart - OPTIONAL but RECOMMENDED
|
||||||
|
# Restarts queue workers every hour to prevent memory leaks
|
||||||
|
0 * * * * cd /home/jobifyg/public_html && php artisan queue:restart >> /dev/null 2>&1
|
||||||
|
|
||||||
|
# Clear old failed jobs - OPTIONAL
|
||||||
|
# Clears failed jobs older than 7 days, runs daily at 4 AM
|
||||||
|
0 4 * * * cd /home/jobifyg/public_html && php artisan queue:flush >> /dev/null 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Verify Cron Jobs Are Running
|
||||||
|
|
||||||
|
After saving your crontab, verify it's active:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List your cron jobs
|
||||||
|
crontab -l
|
||||||
|
|
||||||
|
# Check if cron jobs are running (wait a few minutes)
|
||||||
|
tail -f /home/jobifyg/public_html/storage/logs/laravel.log
|
||||||
|
|
||||||
|
# Check queue worker logs
|
||||||
|
tail -f /home/jobifyg/public_html/storage/logs/queue-worker.log
|
||||||
|
```
|
||||||
|
|
||||||
|
## What Each Cron Job Does
|
||||||
|
|
||||||
|
### 1. Laravel Scheduler (`* * * * * ... schedule:run`)
|
||||||
|
**Frequency:** Every minute
|
||||||
|
**Purpose:** Checks and runs scheduled tasks defined in `bootstrap/app.php`
|
||||||
|
|
||||||
|
**Scheduled Tasks:**
|
||||||
|
- `jobs:fetch` - Fetches new jobs from APIs every 2 hours
|
||||||
|
- `jobs:enrich` - Auto-categorizes and enhances jobs every 6 hours
|
||||||
|
- `jobs:clean` - Removes old jobs (45+ days) daily at 2 AM
|
||||||
|
- `jobs:deduplicate` - Removes duplicate jobs daily at 3 AM
|
||||||
|
- `cache:prune-stale-tags` - Cleans cache hourly
|
||||||
|
|
||||||
|
For detailed explanations and customization options, see [SCHEDULED_TASKS.md](SCHEDULED_TASKS.md)
|
||||||
|
|
||||||
|
### 2. Queue Worker (`* * * * * ... queue:work`)
|
||||||
|
**Frequency:** Every minute
|
||||||
|
**Purpose:** Processes background jobs from the queue
|
||||||
|
|
||||||
|
**Jobs Processed:**
|
||||||
|
- Fetching jobs from external APIs
|
||||||
|
- Processing individual job listings
|
||||||
|
- Email notifications (if configured)
|
||||||
|
- Cache warming
|
||||||
|
- Other background tasks
|
||||||
|
|
||||||
|
**Options Explained:**
|
||||||
|
- `--max-time=50` - Worker runs for max 50 seconds then exits
|
||||||
|
- `--stop-when-empty` - Exits if no jobs are in queue
|
||||||
|
- `--sleep=3` - Waits 3 seconds between jobs
|
||||||
|
- `--tries=3` - Retries failed jobs up to 3 times
|
||||||
|
|
||||||
|
### 3. Queue Restart (`0 * * * * ... queue:restart`)
|
||||||
|
**Frequency:** Every hour
|
||||||
|
**Purpose:** Gracefully restarts queue workers to prevent memory leaks
|
||||||
|
|
||||||
|
### 4. Queue Flush (`0 4 * * * ... queue:flush`)
|
||||||
|
**Frequency:** Daily at 4 AM
|
||||||
|
**Purpose:** Clears old failed jobs from the database
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Cron jobs not running?
|
||||||
|
|
||||||
|
1. **Check crontab is saved:**
|
||||||
|
```bash
|
||||||
|
crontab -l
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Check PHP path:**
|
||||||
|
```bash
|
||||||
|
which php
|
||||||
|
# Use the full path in crontab if needed: /usr/bin/php artisan ...
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Check application path:**
|
||||||
|
```bash
|
||||||
|
pwd
|
||||||
|
# Make sure you're using the correct path in crontab
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Check file permissions:**
|
||||||
|
```bash
|
||||||
|
ls -la /home/jobifyg/public_html/artisan
|
||||||
|
chmod +x /home/jobifyg/public_html/artisan
|
||||||
|
```
|
||||||
|
|
||||||
|
### Jobs not being processed?
|
||||||
|
|
||||||
|
1. **Check queue worker logs:**
|
||||||
|
```bash
|
||||||
|
tail -f storage/logs/queue-worker.log
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Check Laravel logs:**
|
||||||
|
```bash
|
||||||
|
tail -f storage/logs/laravel.log
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Manually run queue worker to see errors:**
|
||||||
|
```bash
|
||||||
|
php artisan queue:work --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Check failed jobs:**
|
||||||
|
```bash
|
||||||
|
php artisan queue:failed
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Retry failed jobs:**
|
||||||
|
```bash
|
||||||
|
php artisan queue:retry all
|
||||||
|
```
|
||||||
|
|
||||||
|
### Jobs are fetched but not appearing?
|
||||||
|
|
||||||
|
1. **Check if job fetch is scheduled:**
|
||||||
|
```bash
|
||||||
|
php artisan schedule:list
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Manually test job fetching:**
|
||||||
|
```bash
|
||||||
|
php artisan jobs:fetch --limit=5
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Check queue:**
|
||||||
|
```bash
|
||||||
|
php artisan queue:work --once --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Tuning
|
||||||
|
|
||||||
|
### Low Traffic Site
|
||||||
|
If your site has low traffic, you can reduce frequency:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run queue worker every 5 minutes instead
|
||||||
|
*/5 * * * * cd /home/jobifyg/public_html && php artisan queue:work --max-time=240 --stop-when-empty --sleep=3 --tries=3 >> storage/logs/queue.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
### High Traffic Site
|
||||||
|
If you need faster job processing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run multiple queue workers
|
||||||
|
* * * * * cd /home/jobifyg/public_html && php artisan queue:work --max-time=50 --stop-when-empty --queue=high,default --sleep=1 --tries=3 >> storage/logs/queue-worker-1.log 2>&1
|
||||||
|
* * * * * cd /home/jobifyg/public_html && php artisan queue:work --max-time=50 --stop-when-empty --queue=default --sleep=1 --tries=3 >> storage/logs/queue-worker-2.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring
|
||||||
|
|
||||||
|
### Check Cron Execution
|
||||||
|
Your hosting control panel may have a cron job log. Check there for execution history.
|
||||||
|
|
||||||
|
### Check Application Health
|
||||||
|
```bash
|
||||||
|
# Visit this URL in your browser (Laravel health check)
|
||||||
|
https://jobifygarden.com/up
|
||||||
|
|
||||||
|
# Check recent jobs
|
||||||
|
php artisan tinker
|
||||||
|
>>> \App\Models\Job::latest()->take(5)->get(['id', 'title', 'created_at']);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monitor Logs
|
||||||
|
```bash
|
||||||
|
# Watch all logs in real-time
|
||||||
|
tail -f storage/logs/*.log
|
||||||
|
|
||||||
|
# Check for errors
|
||||||
|
grep -i error storage/logs/laravel.log | tail -20
|
||||||
|
```
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
1. **Queue Worker Must Keep Running**: The queue worker cron ensures jobs are processed continuously. Without it, jobs will queue but never execute.
|
||||||
|
|
||||||
|
2. **Schedule Must Run Every Minute**: The scheduler cron must run every minute. Laravel internally determines which scheduled tasks should run.
|
||||||
|
|
||||||
|
3. **Time Zone**: Make sure your server's timezone matches your Laravel app timezone (check `config/app.php`).
|
||||||
|
|
||||||
|
4. **Testing**: After setup, wait a few minutes and check logs to verify everything is working.
|
||||||
|
|
||||||
|
5. **Production**: Make sure `APP_ENV=production` and `APP_DEBUG=false` in your `.env` file.
|
||||||
|
|
||||||
|
## Quick Test
|
||||||
|
|
||||||
|
After setting up cron, test immediately:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Manually run scheduler
|
||||||
|
php artisan schedule:run
|
||||||
|
|
||||||
|
# 2. Queue a test job
|
||||||
|
php artisan jobs:fetch Remotive --limit=2
|
||||||
|
|
||||||
|
# 3. Process the queue
|
||||||
|
php artisan queue:work --once --verbose
|
||||||
|
|
||||||
|
# 4. Check if jobs were created
|
||||||
|
php artisan tinker
|
||||||
|
>>> \App\Models\Job::count();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
If you encounter issues:
|
||||||
|
1. Check the troubleshooting section above
|
||||||
|
2. Review logs in `storage/logs/`
|
||||||
|
3. Ensure Redis is working: `php artisan tinker` then `Cache::get('test')`
|
||||||
|
4. Verify database connection works
|
||||||
@@ -220,7 +220,7 @@ The application uses queues for background job processing. You must run a queue
|
|||||||
./vendor/bin/sail artisan queue:work --sleep=3 --tries=3 --timeout=90
|
./vendor/bin/sail artisan queue:work --sleep=3 --tries=3 --timeout=90
|
||||||
```
|
```
|
||||||
|
|
||||||
**Using Supervisor (Production):**
|
**Using Supervisor (Production with Supervisor):**
|
||||||
Create `/etc/supervisor/conf.d/jobifygarden-worker.conf`:
|
Create `/etc/supervisor/conf.d/jobifygarden-worker.conf`:
|
||||||
```ini
|
```ini
|
||||||
[program:jobifygarden-worker]
|
[program:jobifygarden-worker]
|
||||||
@@ -244,6 +244,9 @@ sudo supervisorctl update
|
|||||||
sudo supervisorctl start jobifygarden-worker:*
|
sudo supervisorctl start jobifygarden-worker:*
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Using Cron (Production without Supervisor):**
|
||||||
|
If your hosting provider doesn't have Supervisor, see [CRON_SETUP.md](CRON_SETUP.md) for detailed cron-based setup instructions.
|
||||||
|
|
||||||
### Cron Jobs (Required)
|
### Cron Jobs (Required)
|
||||||
|
|
||||||
Laravel's task scheduler must run every minute. Add this to your crontab:
|
Laravel's task scheduler must run every minute. Add this to your crontab:
|
||||||
|
|||||||
@@ -0,0 +1,367 @@
|
|||||||
|
# Scheduled Tasks Guide for JobifyGarden
|
||||||
|
|
||||||
|
This document explains the optimal scheduling intervals for all automated tasks in JobifyGarden and the reasoning behind them.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
All scheduled tasks are configured in `bootstrap/app.php` and run automatically via the Laravel scheduler (cron job running every minute).
|
||||||
|
|
||||||
|
## Scheduled Tasks
|
||||||
|
|
||||||
|
### 1. Job Fetching (`jobs:fetch`)
|
||||||
|
|
||||||
|
**Interval:** Every 2 hours
|
||||||
|
**Command:** `php artisan jobs:fetch --limit=50`
|
||||||
|
|
||||||
|
**Why this interval:**
|
||||||
|
- **Freshness:** Most job boards update their listings every few hours
|
||||||
|
- **API Rate Limits:** Spacing out requests prevents hitting rate limits
|
||||||
|
- **Resource Management:** Prevents overwhelming your queue and database
|
||||||
|
- **User Experience:** 2-hour intervals ensure users see fresh content without excessive API calls
|
||||||
|
|
||||||
|
**Customization Options:**
|
||||||
|
```php
|
||||||
|
// More frequent (hourly) - for high-traffic sites
|
||||||
|
->hourly()
|
||||||
|
|
||||||
|
// Less frequent (every 4 hours) - for lower traffic or to save resources
|
||||||
|
->everyFourHours()
|
||||||
|
|
||||||
|
// Peak hours only (every 2 hours from 6 AM to 6 PM)
|
||||||
|
->everyTwoHours()->between('6:00', '18:00')
|
||||||
|
```
|
||||||
|
|
||||||
|
**Limit Parameter:**
|
||||||
|
- `--limit=50` fetches up to 50 jobs per source
|
||||||
|
- Adjust based on your API quotas and database capacity
|
||||||
|
- Recommended: 20-100 jobs per fetch cycle
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Job Enrichment (`jobs:enrich`)
|
||||||
|
|
||||||
|
**Interval:** Every 6 hours
|
||||||
|
**Command:** `php artisan jobs:enrich`
|
||||||
|
|
||||||
|
**Why this interval:**
|
||||||
|
- **Processing Time:** Enrichment can be resource-intensive (AI/ML for categorization)
|
||||||
|
- **Batch Efficiency:** Allows multiple fetch cycles to accumulate jobs before enriching
|
||||||
|
- **Priority:** Less urgent than fetching; can run in background
|
||||||
|
- **Resource Balance:** Doesn't compete with peak fetch times
|
||||||
|
|
||||||
|
**What it does:**
|
||||||
|
- Auto-categorizes jobs based on title/description
|
||||||
|
- Detects experience levels (entry, mid, senior, etc.)
|
||||||
|
- Normalizes job data
|
||||||
|
- Enhances job metadata
|
||||||
|
|
||||||
|
**Customization Options:**
|
||||||
|
```php
|
||||||
|
// More frequent (every 4 hours) - if categorization is critical
|
||||||
|
->everyFourHours()
|
||||||
|
|
||||||
|
// Less frequent (twice daily) - to save resources
|
||||||
|
->twiceDaily(1, 13) // 1 AM and 1 PM
|
||||||
|
|
||||||
|
// Only during off-peak hours
|
||||||
|
->dailyAt('03:00')
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Job Deduplication (`jobs:deduplicate`)
|
||||||
|
|
||||||
|
**Interval:** Daily at 3:00 AM
|
||||||
|
**Command:** `php artisan jobs:deduplicate`
|
||||||
|
|
||||||
|
**Why this interval:**
|
||||||
|
- **Daily Cleanup:** Removes duplicates that accumulate from multiple sources
|
||||||
|
- **Off-Peak Hours:** Runs at 3 AM when traffic is lowest
|
||||||
|
- **Post-Fetch:** Runs after fetch cycles have completed
|
||||||
|
- **Database Health:** Keeps database clean without running too frequently
|
||||||
|
|
||||||
|
**What it does:**
|
||||||
|
- Identifies duplicate jobs based on title, company, and location
|
||||||
|
- Removes or merges duplicate entries
|
||||||
|
- Updates job fingerprints
|
||||||
|
- Maintains data integrity
|
||||||
|
|
||||||
|
**Customization Options:**
|
||||||
|
```php
|
||||||
|
// More frequent (every 12 hours) - if duplicates are a major issue
|
||||||
|
->twiceDaily(3, 15) // 3 AM and 3 PM
|
||||||
|
|
||||||
|
// Less frequent (weekly) - if duplicates are rare
|
||||||
|
->weeklyOn(0, '03:00') // Sunday at 3 AM
|
||||||
|
|
||||||
|
// After major fetch cycles
|
||||||
|
->dailyAt('04:00') // After enrichment completes
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Job Cleanup (`jobs:clean`)
|
||||||
|
|
||||||
|
**Interval:** Daily at 2:00 AM
|
||||||
|
**Command:** `php artisan jobs:clean --days=45`
|
||||||
|
|
||||||
|
**Why this interval:**
|
||||||
|
- **Daily Maintenance:** Removes expired jobs every day
|
||||||
|
- **Off-Peak Hours:** 2 AM has minimal user activity
|
||||||
|
- **Before Deduplication:** Runs before deduplication to remove stale data first
|
||||||
|
- **Database Performance:** Prevents database bloat
|
||||||
|
|
||||||
|
**What it does:**
|
||||||
|
- Removes jobs older than 45 days
|
||||||
|
- Deletes expired job listings
|
||||||
|
- Cleans up soft-deleted jobs
|
||||||
|
- Optimizes database performance
|
||||||
|
|
||||||
|
**Retention Period Options:**
|
||||||
|
```php
|
||||||
|
// Shorter retention (30 days) - for high-volume sites
|
||||||
|
'jobs:clean --days=30'
|
||||||
|
|
||||||
|
// Longer retention (60-90 days) - for SEO or archival
|
||||||
|
'jobs:clean --days=60'
|
||||||
|
|
||||||
|
// Remove only expired jobs
|
||||||
|
'jobs:clean --expired-only'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Customization Options:**
|
||||||
|
```php
|
||||||
|
// Weekly cleanup instead of daily
|
||||||
|
->weeklyOn(0, '02:00')
|
||||||
|
|
||||||
|
// Twice daily (aggressive cleanup)
|
||||||
|
->twiceDaily(2, 14)
|
||||||
|
|
||||||
|
// Monthly cleanup (for archival sites)
|
||||||
|
->monthlyOn(1, '02:00')
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Cache Pruning (`cache:prune-stale-tags`)
|
||||||
|
|
||||||
|
**Interval:** Hourly
|
||||||
|
**Command:** `php artisan cache:prune-stale-tags`
|
||||||
|
|
||||||
|
**Why this interval:**
|
||||||
|
- **Cache Health:** Removes stale cache entries regularly
|
||||||
|
- **Memory Management:** Prevents Redis/cache bloat
|
||||||
|
- **Frequent Cleanup:** Cache tags can accumulate quickly
|
||||||
|
- **Low Impact:** Fast operation, doesn't affect performance
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommended Schedules by Site Size
|
||||||
|
|
||||||
|
### Small Site (<1,000 jobs, <1,000 visitors/day)
|
||||||
|
|
||||||
|
```php
|
||||||
|
$schedule->command('jobs:fetch --limit=30')
|
||||||
|
->everyFourHours()
|
||||||
|
->withoutOverlapping();
|
||||||
|
|
||||||
|
$schedule->command('jobs:enrich')
|
||||||
|
->twiceDaily(2, 14);
|
||||||
|
|
||||||
|
$schedule->command('jobs:deduplicate')
|
||||||
|
->weeklyOn(0, '03:00');
|
||||||
|
|
||||||
|
$schedule->command('jobs:clean --days=60')
|
||||||
|
->weekly();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Medium Site (1,000-10,000 jobs, 1,000-10,000 visitors/day)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Current default configuration in bootstrap/app.php
|
||||||
|
$schedule->command('jobs:fetch --limit=50')
|
||||||
|
->everyTwoHours()
|
||||||
|
->withoutOverlapping();
|
||||||
|
|
||||||
|
$schedule->command('jobs:enrich')
|
||||||
|
->everySixHours();
|
||||||
|
|
||||||
|
$schedule->command('jobs:deduplicate')
|
||||||
|
->dailyAt('03:00');
|
||||||
|
|
||||||
|
$schedule->command('jobs:clean --days=45')
|
||||||
|
->dailyAt('02:00');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Large Site (10,000+ jobs, 10,000+ visitors/day)
|
||||||
|
|
||||||
|
```php
|
||||||
|
$schedule->command('jobs:fetch --limit=100')
|
||||||
|
->hourly()
|
||||||
|
->withoutOverlapping()
|
||||||
|
->onOneServer()
|
||||||
|
->runInBackground();
|
||||||
|
|
||||||
|
$schedule->command('jobs:enrich')
|
||||||
|
->everyFourHours()
|
||||||
|
->runInBackground();
|
||||||
|
|
||||||
|
$schedule->command('jobs:deduplicate')
|
||||||
|
->twiceDaily(3, 15)
|
||||||
|
->runInBackground();
|
||||||
|
|
||||||
|
$schedule->command('jobs:clean --days=30')
|
||||||
|
->dailyAt('02:00')
|
||||||
|
->runInBackground();
|
||||||
|
|
||||||
|
// Add sitemap regeneration
|
||||||
|
$schedule->command('sitemap:generate')
|
||||||
|
->dailyAt('04:00')
|
||||||
|
->runInBackground();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### 1. Monitoring
|
||||||
|
|
||||||
|
Always monitor your scheduled tasks:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View scheduled tasks
|
||||||
|
php artisan schedule:list
|
||||||
|
|
||||||
|
# Test schedule (simulates next minute)
|
||||||
|
php artisan schedule:test
|
||||||
|
|
||||||
|
# Run schedule manually
|
||||||
|
php artisan schedule:run
|
||||||
|
|
||||||
|
# Check logs
|
||||||
|
tail -f storage/logs/laravel.log | grep -i "schedule\|fetch\|enrich\|deduplicate\|clean"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Resource Management
|
||||||
|
|
||||||
|
- Use `->runInBackground()` for heavy tasks to prevent blocking
|
||||||
|
- Use `->withoutOverlapping()` to prevent concurrent runs
|
||||||
|
- Use `->onOneServer()` if running multiple app servers
|
||||||
|
|
||||||
|
### 3. Error Handling
|
||||||
|
|
||||||
|
Add notifications for failures:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$schedule->command('jobs:fetch')
|
||||||
|
->everyTwoHours()
|
||||||
|
->onFailure(function () {
|
||||||
|
// Log error, send notification, etc.
|
||||||
|
Log::error('Job fetch failed!');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Performance Optimization
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Run during off-peak hours only
|
||||||
|
$schedule->command('jobs:fetch')
|
||||||
|
->everyTwoHours()
|
||||||
|
->between('6:00', '22:00'); // Only 6 AM to 10 PM
|
||||||
|
|
||||||
|
// Avoid peak hours
|
||||||
|
$schedule->command('jobs:deduplicate')
|
||||||
|
->dailyAt('03:00')
|
||||||
|
->unlessBetween('08:00', '18:00'); // Not during business hours
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task Dependencies
|
||||||
|
|
||||||
|
The order matters! Run tasks in this sequence:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. jobs:fetch (2 AM, 4 AM, 6 AM, ...)
|
||||||
|
↓
|
||||||
|
2. jobs:clean (2 AM) - Remove old/expired first
|
||||||
|
↓
|
||||||
|
3. jobs:deduplicate (3 AM) - Then remove duplicates
|
||||||
|
↓
|
||||||
|
4. jobs:enrich (6 AM, 12 PM, 6 PM, 12 AM) - Finally enrich
|
||||||
|
```
|
||||||
|
|
||||||
|
This ensures:
|
||||||
|
- Old jobs are removed before deduplication
|
||||||
|
- Deduplication happens before enrichment
|
||||||
|
- Enrichment works on clean, deduplicated data
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Jobs not being fetched?
|
||||||
|
|
||||||
|
1. Check if scheduler is running:
|
||||||
|
```bash
|
||||||
|
php artisan schedule:list
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Verify cron job is active:
|
||||||
|
```bash
|
||||||
|
crontab -l
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Test manual fetch:
|
||||||
|
```bash
|
||||||
|
php artisan jobs:fetch --limit=5
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Check API credentials in `.env`
|
||||||
|
|
||||||
|
### Duplicates still appearing?
|
||||||
|
|
||||||
|
1. Run deduplication manually:
|
||||||
|
```bash
|
||||||
|
php artisan jobs:deduplicate --force
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Check fingerprint generation logic
|
||||||
|
|
||||||
|
3. Consider running deduplication more frequently
|
||||||
|
|
||||||
|
### Database growing too large?
|
||||||
|
|
||||||
|
1. Reduce retention period:
|
||||||
|
```php
|
||||||
|
'jobs:clean --days=30'
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Run cleanup more frequently:
|
||||||
|
```php
|
||||||
|
->twiceDaily(2, 14)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Check for failed deletions:
|
||||||
|
```bash
|
||||||
|
php artisan jobs:clean --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
**Optimal Schedule (Default):**
|
||||||
|
- **Fetch:** Every 2 hours
|
||||||
|
- **Enrich:** Every 6 hours
|
||||||
|
- **Deduplicate:** Daily at 3 AM
|
||||||
|
- **Clean:** Daily at 2 AM (45-day retention)
|
||||||
|
|
||||||
|
This provides a good balance of:
|
||||||
|
✅ Fresh content
|
||||||
|
✅ Resource efficiency
|
||||||
|
✅ Database health
|
||||||
|
✅ User experience
|
||||||
|
✅ API compliance
|
||||||
|
|
||||||
|
Adjust based on your specific needs, traffic patterns, and resource constraints.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
We need a tags system for the jobs.
|
||||||
|
Also, on the jobs table we need a is_curated bool column.
|
||||||
|
a command that gets jobs that were not curated, does an POST api call that i will give later to you with the job name and description and the response will be an array of tags.
|
||||||
|
we should save those tags and associate it with the job.
|
||||||
|
we should also display the tags in the job page,
|
||||||
+49
-10
@@ -16,20 +16,59 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
//
|
//
|
||||||
})
|
})
|
||||||
->withSchedule(function (Schedule $schedule): void {
|
->withSchedule(function (Schedule $schedule): void {
|
||||||
// Fetch jobs from all sources hourly
|
// =========================================================================
|
||||||
$schedule->command('jobs:fetch --limit=100')
|
// Job Fetching - Fetch fresh jobs from external APIs
|
||||||
->hourly()
|
// =========================================================================
|
||||||
|
|
||||||
|
// Fetch jobs every 2 hours to keep listings fresh
|
||||||
|
// Limit per source to avoid rate limits and keep queue manageable
|
||||||
|
$schedule->command('jobs:fetch --limit=50')
|
||||||
|
->everyTwoHours()
|
||||||
->withoutOverlapping()
|
->withoutOverlapping()
|
||||||
->onOneServer();
|
->onOneServer()
|
||||||
|
->runInBackground();
|
||||||
|
|
||||||
// Clean up old jobs daily at 2 AM
|
// =========================================================================
|
||||||
$schedule->command('jobs:clean --days=30')
|
// Job Enrichment - Auto-categorize and enhance job data
|
||||||
->dailyAt('02:00')
|
// =========================================================================
|
||||||
->onOneServer();
|
|
||||||
|
|
||||||
// Deduplicate jobs weekly on Sunday at 3 AM
|
// Enrich new jobs every 6 hours (categorization, experience level detection)
|
||||||
|
// This runs after jobs have been fetched to categorize uncategorized jobs
|
||||||
|
$schedule->command('jobs:enrich')
|
||||||
|
->everySixHours()
|
||||||
|
->withoutOverlapping()
|
||||||
|
->onOneServer()
|
||||||
|
->runInBackground();
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Job Deduplication - Remove duplicate job listings
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// Deduplicate jobs daily at 3 AM (after fetch cycles have completed)
|
||||||
|
// Daily is better than weekly to keep listings clean
|
||||||
$schedule->command('jobs:deduplicate')
|
$schedule->command('jobs:deduplicate')
|
||||||
->weeklyOn(0, '03:00')
|
->dailyAt('03:00')
|
||||||
|
->onOneServer()
|
||||||
|
->runInBackground();
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Job Cleanup - Remove expired and old jobs
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// Clean up expired and old jobs daily at 2 AM
|
||||||
|
// Keeps database lean and removes stale listings
|
||||||
|
$schedule->command('jobs:clean --days=45')
|
||||||
|
->dailyAt('02:00')
|
||||||
|
->onOneServer()
|
||||||
|
->runInBackground();
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Cache Management - Keep caches fresh
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// Prune stale cache tags hourly
|
||||||
|
$schedule->command('cache:prune-stale-tags')
|
||||||
|
->hourly()
|
||||||
->onOneServer();
|
->onOneServer();
|
||||||
})
|
})
|
||||||
->withExceptions(function (Exceptions $exceptions): void {
|
->withExceptions(function (Exceptions $exceptions): void {
|
||||||
|
|||||||
Generated
+3
-3
@@ -9221,12 +9221,12 @@
|
|||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": [],
|
"stability-flags": {},
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "^8.3"
|
"php": "^8.3"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": {},
|
||||||
"plugin-api-version": "2.2.0"
|
"plugin-api-version": "2.9.0"
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,6 @@
|
|||||||
|
This favicon was generated using the following font:
|
||||||
|
|
||||||
|
- Font Title: Leckerli One
|
||||||
|
- Font Author: undefined
|
||||||
|
- Font Source: https://fonts.gstatic.com/s/leckerlione/v21/V8mCoQH8VCsNttEnxnGQ-1itLZxcBtItFw.ttf
|
||||||
|
- Font License: undefined)
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 770 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1 @@
|
|||||||
|
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Queue Worker Script for JobifyGarden
|
||||||
|
# This script runs the queue worker and ensures it doesn't run if already running
|
||||||
|
#
|
||||||
|
|
||||||
|
# Get the directory where this script is located
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
cd "$DIR"
|
||||||
|
|
||||||
|
# Check if queue worker is already running
|
||||||
|
if pgrep -f "artisan queue:work" > /dev/null; then
|
||||||
|
echo "Queue worker already running, skipping..."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run the queue worker
|
||||||
|
# --max-time=50 ensures it runs for max 50 seconds
|
||||||
|
# --stop-when-empty exits when queue is empty
|
||||||
|
# --sleep=3 waits 3 seconds between jobs
|
||||||
|
# --tries=3 retries failed jobs 3 times
|
||||||
|
php artisan queue:work --max-time=50 --stop-when-empty --sleep=3 --tries=3 >> storage/logs/queue-worker.log 2>&1
|
||||||
Reference in New Issue
Block a user