Add queue management dashboard (#15202)

Adds a comprehensive queue management interface to the admin panel for
viewing and managing background jobs.

**Features:**
- Queue detail pages showing paginated job lists (50 per page)
- Filter jobs by state: completed, failed, active, waiting, delayed,
paused
- Checkbox selection with bulk actions (delete jobs, retry failed jobs)
- Per-job dropdown menu for individual retry/delete
- Expandable rows showing error messages, stack traces, and job data
- Relative timestamps with hover tooltips
- Display attempt counts on failed jobs
- Dynamic retention policy info from backend

**Changes:**
- Backend: New AdminPanelQueueService with GraphQL endpoints for job
listing, retry, and delete
- Frontend: Queue detail page with QueueJobsTable component
- Updated retention policy: completed jobs kept 4 hours, failed jobs
kept 7 days (max 1000 each)
- Added JobState enum for type safety

<img width="634" height="696" alt="Screenshot_2025-10-20_at_11 45 25"
src="https://github.com/user-attachments/assets/c67bcd27-26cf-47f5-9575-3cd5684d006b"
/>
<img width="484" height="680" alt="Screenshot_2025-10-20_at_11 45 14"
src="https://github.com/user-attachments/assets/68725cc6-b3ec-4098-99ca-f9a717d6f8f1"
/>
<img width="490" height="643" alt="Screenshot_2025-10-20_at_11 45 05"
src="https://github.com/user-attachments/assets/b68a5809-33ff-4452-b48b-741aff7f1dd6"
/>



<img width="685" height="662" alt="Screenshot 2025-10-20 at 13 15 01"
src="https://github.com/user-attachments/assets/eeb5207b-de5c-4b18-bdde-392892053dab"
/>
This commit is contained in:
Félix Malfait
2025-10-21 16:02:50 +02:00
committed by GitHub
parent 27f50c4f4e
commit f7421c5fc0
144 changed files with 2914 additions and 955 deletions
@@ -0,0 +1,6 @@
export const QUEUE_RETENTION = {
completedMaxAge: 14400, // 4 hours (4*3600s)
completedMaxCount: 1000,
failedMaxAge: 604800, // 7 days (7*24*3600s)
failedMaxCount: 1000,
};
@@ -18,6 +18,7 @@ import { type MessageQueueDriver } from 'src/engine/core-modules/message-queue/d
import { type MessageQueueJob } from 'src/engine/core-modules/message-queue/interfaces/message-queue-job.interface';
import { type MessageQueueWorkerOptions } from 'src/engine/core-modules/message-queue/interfaces/message-queue-worker-options.interface';
import { QUEUE_RETENTION } from 'src/engine/core-modules/message-queue/constants/queue-retention.constants';
import { type MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
import { getJobKey } from 'src/engine/core-modules/message-queue/utils/get-job-key.util';
import { MESSAGE_QUEUE_PRIORITY } from 'src/engine/core-modules/message-queue/message-queue-priority.constant';
@@ -112,8 +113,14 @@ export class BullMQDriver implements MessageQueueDriver, OnModuleDestroy {
const queueOptions: JobsOptions = {
priority: options?.priority,
repeat: options?.repeat,
removeOnComplete: true,
removeOnFail: 100,
removeOnComplete: {
age: QUEUE_RETENTION.completedMaxAge,
count: QUEUE_RETENTION.completedMaxCount,
},
removeOnFail: {
age: QUEUE_RETENTION.failedMaxAge,
count: QUEUE_RETENTION.failedMaxCount,
},
};
await this.queueMap[queueName].upsertJobScheduler(
@@ -170,8 +177,14 @@ export class BullMQDriver implements MessageQueueDriver, OnModuleDestroy {
jobId: options?.id ? `${options.id}-${v4()}` : undefined, // We add V4() to id to make sure ids are uniques so we can add a waiting job when a job related with the same option.id is running
priority: options?.priority ?? MESSAGE_QUEUE_PRIORITY[queueName],
attempts: 1 + (options?.retryLimit || 0),
removeOnComplete: true,
removeOnFail: 100,
removeOnComplete: {
age: QUEUE_RETENTION.completedMaxAge,
count: QUEUE_RETENTION.completedMaxCount,
},
removeOnFail: {
age: QUEUE_RETENTION.failedMaxAge,
count: QUEUE_RETENTION.failedMaxCount,
},
delay: options?.delay,
};