An open API service indexing awesome lists of open source software.

https://github.com/tasmidur/agenda-schedular


https://github.com/tasmidur/agenda-schedular

Last synced: 3 months ago
JSON representation

Awesome Lists containing this project

README

        

If you want to place the `jobHandlers` mapping directly in the `jobs.js` configuration file, you can refactor the code to make it more centralized and maintainable. This approach ensures that all job-related configurations, including handlers, are defined in one place.

Here’s how you can update the `jobs.js` file and the rest of the application to accommodate this change:

---

### Updated Folder Structure
```
nodejs-scheduler/
├── src/
│ ├── config/ # Configuration files
│ │ ├── db.js
│ │ └── jobs.js # Job configurations and handlers
│ ├── core/ # Core application logic
│ │ ├── events/ # Event definitions
│ │ │ └── userEvents.js
│ │ └── services/ # Service classes
│ │ ├── agendaService.js
│ │ ├── eventService.js
│ │ └── jobService.js
│ ├── infrastructure/ # Infrastructure setup
│ │ └── agendaSetup.js # Agenda initialization
│ └── index.js # Entry point
├── .env # Environment variables
└── package.json
```

---

### Step 1: Environment Variables (`.env`)
Add MongoDB connection details:
```env
MONGO_URI=mongodb://localhost:27017/agenda
```

---

### Step 2: Database Configuration (`src/config/db.js`)
Set up MongoDB connection:
```javascript
import mongoose from 'mongoose';
import 'dotenv/config';

const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log('MongoDB connected...');
} catch (error) {
console.error('MongoDB connection error:', error);
process.exit(1);
}
};

export default connectDB;
```

---

### Step 3: Job Configuration and Handlers (`src/config/jobs.js`)
Define jobs, their handlers, and schedules in one place:
```javascript
// Job Handlers
const processTask = async (job) => {
const { data } = job.attrs;
console.log('Processing task with data:', data);
// Add your job logic here
};

const sendEmail = async (job) => {
const { data } = job.attrs;
console.log('Sending email to:', data.email);
// Add your email sending logic here
};

// Job Configuration
export const jobs = [
{
name: 'process-task',
handler: processTask, // Direct reference to the handler
schedule: '0 12 * * *', // Daily at 12 PM (noon)
},
{
name: 'send-email',
handler: sendEmail, // Direct reference to the handler
schedule: '2025-02-01T00:00:00', // Specific date: 01-02-2025 at midnight
},
];
```

---

### Step 4: Agenda Setup (`src/infrastructure/agendaSetup.js`)
Initialize Agenda and register jobs using the configuration from `jobs.js`:
```javascript
import Agenda from 'agenda';
import 'dotenv/config';
import { jobs } from '../config/jobs.js';

const agenda = new Agenda({ db: { address: process.env.MONGO_URI } });

// Register jobs
jobs.forEach((job) => {
agenda.define(job.name, job.handler);

if (job.schedule) {
if (typeof job.schedule === 'string' && job.schedule.split(' ').length === 5) {
// Cron syntax
agenda.every(job.schedule, job.name);
} else {
// Specific date
agenda.schedule(new Date(job.schedule), job.name);
}
}
});

export default agenda;
```

---

### Step 5: Agenda Service (`src/core/services/agendaService.js`)
Create a service to interact with Agenda:
```javascript
import agenda from '../../infrastructure/agendaSetup.js';

class AgendaService {
async start() {
await agenda.start();
console.log('Agenda scheduler started...');
}

queueJob(name, data = {}) {
agenda.now(name, data);
}
}

export default new AgendaService();
```

---

### Step 6: Event Service (`src/core/services/eventService.js`)
Create a service to handle event emission and listening:
```javascript
import { EventEmitter } from 'events';
import agendaService from './agendaService.js';

class EventService extends EventEmitter {
constructor() {
super();
this.setupListeners();
}

setupListeners() {
// Listen for user.signup event
this.on('user.signup', (userData) => {
console.log('User signed up:', userData);
// Queue a job
agendaService.queueJob('process-task', { data: userData });
});

// Listen for send.email event
this.on('send.email', (emailData) => {
console.log('Email requested:', emailData);
// Queue a job
agendaService.queueJob('send-email', { data: emailData });
});
}
}

export default new EventService();
```

---

### Step 7: Event Definitions (`src/core/events/userEvents.js`)
Emit events to test the system:
```javascript
import eventService from '../services/eventService.js';

// Simulate a user signing up
const userData = { id: 1, name: 'John Doe', email: '[email protected]' };
eventService.emit('user.signup', userData);

// Simulate sending an email
const emailData = { email: '[email protected]', subject: 'Welcome!', body: 'Thank you for signing up.' };
eventService.emit('send.email', emailData);
```

---

### Step 8: Entry Point (`src/index.js`)
Initialize the application:
```javascript
import connectDB from './config/db.js';
import agendaService from './core/services/agendaService.js';
import './core/events/userEvents.js'; // Emit events

// Connect to MongoDB
connectDB();

// Start Agenda
agendaService.start();
```

---

### Step 9: Run the Application
1. Start MongoDB:
```bash
mongod
```

2. Run the application:
```bash
node src/index.js
```

---

### Expected Output
When you run the application, you should see the following in the console:
```
MongoDB connected...
Agenda scheduler started...
User signed up: { id: 1, name: 'John Doe', email: '[email protected]' }
Processing task with data: { id: 1, name: 'John Doe', email: '[email protected]' }
Email requested: { email: '[email protected]', subject: 'Welcome!', body: 'Thank you for signing up.' }
```

Additionally:
- The `process-task` job will run daily at 12 PM.
- The `send-email` job will run once at midnight on February 1, 2025.

---

### Key Benefits
1. **Centralized Configuration**:
- All job-related configurations (handlers, schedules) are defined in `jobs.js`.

2. **Separation of Concerns**:
- Handlers are defined alongside their configurations, making it easier to manage.

3. **Scalability**:
- Adding new jobs is as simple as adding a new entry to the `jobs` array in `jobs.js`.

This approach adheres to **SOLID principles** and **best practices**, making the application modular, maintainable, and scalable. Let me know if you need further assistance!