Skip to content

Commit 837b2dd

Browse files
skitsanosclaude
andcommitted
fix: resolve scheduler task runner duplicate registration issues
- Remove duplicate scheduler initialization from src/index.js - Enhance task cleanup logic to find and remove all scheduler tasks by name - Improve watchdog to detect and report multiple task runner conflicts - Add comprehensive logging throughout scheduler initialization process - Fix scheduler task collection creation and verification - Eliminate legacy scheduler task accumulation Scheduler system now properly registers exactly one task runner and watchdog, eliminating the continuous "task runner not found" warnings. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent e50c139 commit 837b2dd

File tree

3 files changed

+59
-47
lines changed

3 files changed

+59
-47
lines changed

src/builder/scheduler/index.js

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -163,21 +163,32 @@ const scheduler = {
163163
this.context = context;
164164

165165
// Ensure the scheduledTasks collection exists
166-
if (!db._collection('scheduledTasks')) {
167-
console.warn('scheduledTasks collection not found. Creating it now.');
168-
db._createDocumentCollection('scheduledTasks');
169-
170-
// Create required indexes
171-
const taskCollection = db._collection('scheduledTasks');
172-
taskCollection.ensureIndex({ type: 'hash', fields: ['name'] });
173-
taskCollection.ensureIndex({ type: 'skiplist', fields: ['nextRun'] });
174-
taskCollection.ensureIndex({ type: 'hash', fields: ['status'] });
166+
try {
167+
if (!db._collection('scheduledTasks')) {
168+
console.log('scheduledTasks collection not found. Creating it now.');
169+
const collection = db._createDocumentCollection('scheduledTasks');
170+
console.log(`Created scheduledTasks collection with key: ${collection._key}`);
171+
172+
// Create required indexes
173+
const taskCollection = db._collection('scheduledTasks');
174+
taskCollection.ensureIndex({ type: 'hash', fields: ['name'] });
175+
taskCollection.ensureIndex({ type: 'skiplist', fields: ['nextRun'] });
176+
taskCollection.ensureIndex({ type: 'hash', fields: ['status'] });
177+
console.log('Created indexes for scheduledTasks collection');
178+
} else {
179+
console.log('scheduledTasks collection already exists');
180+
}
181+
} catch (collectionError) {
182+
console.error('Error creating scheduledTasks collection:', collectionError.message);
183+
throw collectionError;
175184
}
176185

177186
// Initialize email service
178187
emailService.init(context);
179188

189+
console.log('Setting up scheduler task runner...');
180190
this.setupTaskRunner();
191+
console.log('Scheduler initialization completed');
181192
return this;
182193
},
183194

@@ -196,12 +207,21 @@ const scheduler = {
196207
// Clean up all existing scheduler-related tasks first
197208
try {
198209
const allTasks = tasks.get();
199-
for (const taskId in allTasks) {
200-
if (taskId.includes('scheduler')) {
201-
console.log(`Cleaning up existing scheduler task: ${taskId}`);
202-
tasks.unregister(taskId);
210+
const taskIds = Object.keys(allTasks);
211+
212+
for (const taskId of taskIds) {
213+
const task = allTasks[taskId];
214+
if (task.name && (task.name.includes('scheduler') || task.name === 'scheduler-task-runner' || task.name === 'scheduler-watchdog')) {
215+
console.log(`Cleaning up existing scheduler task: ${taskId} (${task.name})`);
216+
try {
217+
tasks.unregister(taskId);
218+
} catch (unregError) {
219+
console.warn(`Failed to unregister task ${taskId}: ${unregError.message}`);
220+
}
203221
}
204222
}
223+
224+
console.log(`Cleaned up ${taskIds.filter(id => allTasks[id].name && allTasks[id].name.includes('scheduler')).length} scheduler-related tasks`);
205225
} catch (error) {
206226
console.log('No existing scheduler tasks found or error during cleanup:', error.message);
207227
}
@@ -258,15 +278,7 @@ const scheduler = {
258278

259279
// Register a watchdog task that ensures the main task runner is active
260280
const watchdogTaskName = 'scheduler-watchdog';
261-
try {
262-
const existingWatchdog = tasks.get(watchdogTaskName);
263-
if (existingWatchdog) {
264-
console.log('Unregistering existing scheduler watchdog');
265-
tasks.unregister(watchdogTaskName);
266-
}
267-
} catch (error) {
268-
console.log('No existing scheduler watchdog found (expected for first install)');
269-
}
281+
// Note: Watchdog cleanup is handled in the general cleanup above
270282

271283
tasks.register({
272284
name: watchdogTaskName,
@@ -276,14 +288,21 @@ const scheduler = {
276288
// Import tasks module inside the function
277289
const tasksModule = require('@arangodb/tasks');
278290

279-
// Check if the main task runner exists
291+
// Check if the main task runner exists by looking for any active task with the correct name
280292
try {
281-
tasksModule.get('scheduler-task-runner');
282-
// Task exists, all good
293+
const allTasks = tasksModule.get();
294+
const taskRunners = Object.keys(allTasks).filter(id =>
295+
allTasks[id].name === 'scheduler-task-runner'
296+
);
297+
298+
if (taskRunners.length === 0) {
299+
console.warn('Scheduler task runner not found. Watchdog detected missing task runner.');
300+
} else if (taskRunners.length > 1) {
301+
console.warn(`Multiple scheduler task runners found (${taskRunners.length}). This may cause conflicts.`);
302+
}
303+
// If exactly 1 task runner exists, everything is fine
283304
} catch (taskNotFoundError) {
284-
console.warn('Scheduler task runner not found. Watchdog detected missing task runner.');
285-
// Note: Re-registration would need to be handled differently
286-
// For now, just log the issue
305+
console.warn('Error checking scheduler task runner:', taskNotFoundError.message);
287306
}
288307
} catch (error) {
289308
console.error('Error in scheduler watchdog:', error.message);

src/index.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,11 @@
77
*/
88
const builder = require('./builder/index');
99
const rateLimiter = require('./builder/middleware/rate-limiter');
10-
const scheduler = require('./builder/scheduler');
1110

1211
// Initialize the Foxx Builder
1312
builder.init();
1413

15-
// Initialize the scheduler
16-
scheduler.init(module.context);
17-
console.log('Task scheduler initialized');
14+
// Note: Scheduler is initialized in setup.js to avoid duplicate registrations
1815

1916
// Get configuration
2017
const {

src/setup.js

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -221,22 +221,18 @@ if (rolesCollection.count() === 0) {
221221
// Initialize scheduler service
222222
console.log('Initializing scheduler service...');
223223
try {
224-
// Check if required collections exist
225-
if (!db._collection('scheduledTasks')) {
226-
console.error('scheduledTasks collection not found. Scheduler initialization failed.');
227-
} else {
228-
scheduler.init(module.context);
229-
console.log('Scheduler service initialized successfully');
224+
// The scheduler.init() method will create the collection if it doesn't exist
225+
scheduler.init(module.context);
226+
console.log('Scheduler service initialized successfully');
230227

231-
// Activate any tasks that should be running
232-
const count = db._query(`
233-
FOR task IN scheduledTasks
234-
FILTER task.status IN ['active', 'retry-scheduled']
235-
UPDATE task WITH { updatedAt: ${new Date().getTime()} } IN scheduledTasks
236-
RETURN 1
237-
`).toArray().length;
238-
console.log(`Activated ${count} scheduled tasks`);
239-
}
228+
// Activate any tasks that should be running
229+
const count = db._query(`
230+
FOR task IN scheduledTasks
231+
FILTER task.status IN ['active', 'retry-scheduled']
232+
UPDATE task WITH { updatedAt: ${new Date().getTime()} } IN scheduledTasks
233+
RETURN 1
234+
`).toArray().length;
235+
console.log(`Activated ${count} scheduled tasks`);
240236
} catch (error) {
241237
console.error(`Error initializing scheduler service: ${error.message}`);
242238
}

0 commit comments

Comments
 (0)