Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added prioritized and waiting-children support #634

Merged
merged 1 commit into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/api/src/constants/statuses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,15 @@ export const STATUSES = {
delayed: 'delayed',
paused: 'paused',
} as const;

export const STATUSES_EXT = {
latest: 'latest',
active: 'active',
waiting: 'waiting',
'waiting-children': 'waiting-children',
'prioritized': 'prioritized',
completed: 'completed',
failed: 'failed',
delayed: 'delayed',
paused: 'paused',
} as const;
19 changes: 7 additions & 12 deletions packages/api/src/handlers/queues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
QueueJob,
Status,
} from '../../typings/app';
import { STATUSES } from '../constants/statuses';
import { BaseAdapter } from '../queueAdapters/base';

export const formatJob = (job: QueueJob, queue: BaseAdapter): AppJob => {
Expand All @@ -35,15 +34,6 @@ export const formatJob = (job: QueueJob, queue: BaseAdapter): AppJob => {
};
};

const allStatuses: JobStatus[] = [
STATUSES.active,
STATUSES.completed,
STATUSES.delayed,
STATUSES.failed,
STATUSES.paused,
STATUSES.waiting,
];

function getPagination(
statuses: JobStatus[],
counts: JobCounts,
Expand Down Expand Up @@ -73,11 +63,13 @@ async function getAppQueues(
const isActiveQueue = decodeURIComponent(query.activeQueue) === queueName;
const jobsPerPage = +query.jobsPerPage || 10;

const possibleJobStatuses = queue.getPossibleJobStatuses()

const status =
!isActiveQueue || query.status === 'latest' ? allStatuses : [query.status as JobStatus];
!isActiveQueue || query.status === 'latest' ? possibleJobStatuses : [query.status as JobStatus];
const currentPage = +query.page || 1;

const counts = await queue.getJobCounts(...allStatuses);
const counts = await queue.getJobCounts(...possibleJobStatuses);
const isPaused = await queue.isPaused();

const pagination = getPagination(status, counts, currentPage, jobsPerPage);
Expand All @@ -87,9 +79,12 @@ async function getAppQueues(

const description = queue.getDescription() || undefined;

const possibleStatuses = queue.getPossibleStatuses()

return {
name: queueName,
description,
possibleStatuses,
counts: counts as Record<Status, number>,
jobs: jobs.filter(Boolean).map((job) => formatJob(job, queue)),
pagination,
Expand Down
5 changes: 5 additions & 0 deletions packages/api/src/queueAdapters/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
JobStatus,
QueueAdapterOptions,
QueueJob,
Status,
} from '../../typings/app';

export abstract class BaseAdapter {
Expand Down Expand Up @@ -69,4 +70,8 @@ export abstract class BaseAdapter {
public abstract empty(): Promise<void>;

public abstract promoteAll(): Promise<void>;

public abstract getPossibleStatuses(): Status[]

public abstract getPossibleJobStatuses(): JobStatus[]
}
14 changes: 11 additions & 3 deletions packages/api/src/queueAdapters/bull.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Job, Queue } from 'bull';
import { JobCleanStatus, JobCounts, JobStatus, QueueAdapterOptions } from '../../typings/app';
import { JobCleanStatus, JobCounts, JobStatus, QueueAdapterOptions, Status } from '../../typings/app';
import { STATUSES } from '../constants/statuses';
import { BaseAdapter } from './base';

Expand Down Expand Up @@ -29,7 +29,7 @@ export class BullAdapter extends BaseAdapter {
});
}

public getJobs(jobStatuses: JobStatus[], start?: number, end?: number): Promise<Job[]> {
public getJobs(jobStatuses: JobStatus<'bull'>[], start?: number, end?: number): Promise<Job[]> {
return this.queue.getJobs(jobStatuses, start, end).then((jobs) =>
jobs.map((job) => {
if (typeof job?.attemptsMade === 'number') {
Expand All @@ -42,7 +42,7 @@ export class BullAdapter extends BaseAdapter {
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
public getJobCounts(..._jobStatuses: JobStatus[]): Promise<JobCounts> {
public getJobCounts(..._jobStatuses: JobStatus<'bull'>[]): Promise<JobCounts> {
return this.queue.getJobCounts() as unknown as Promise<JobCounts>;
}

Expand Down Expand Up @@ -70,4 +70,12 @@ export class BullAdapter extends BaseAdapter {
const jobs = await this.getJobs([STATUSES.delayed]);
await Promise.all(jobs.map((job) => job.promote()));
}

public getPossibleStatuses(): Status<'bull'>[] {
return ['latest', 'active', 'waiting','completed', 'failed', 'delayed', 'paused']
}

public getPossibleJobStatuses(): JobStatus<'bull'>[] {
return ['active', 'waiting','completed', 'failed', 'delayed', 'paused']
}
}
10 changes: 9 additions & 1 deletion packages/api/src/queueAdapters/bullMQ.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Job, Queue } from 'bullmq';
import { JobCleanStatus, JobCounts, JobStatus, QueueAdapterOptions } from '../../typings/app';
import { JobCleanStatus, JobCounts, JobStatus, QueueAdapterOptions, Status } from '../../typings/app';
import { STATUSES } from '../constants/statuses';
import { BaseAdapter } from './base';

Expand Down Expand Up @@ -62,4 +62,12 @@ export class BullMQAdapter extends BaseAdapter {
await Promise.all(jobs.map((job) => job.promote()));
}
}

public getPossibleStatuses(): Status[] {
return ['latest', 'active', 'waiting', 'waiting-children', 'prioritized', 'completed', 'failed', 'delayed', 'paused']
}

public getPossibleJobStatuses(): JobStatus[] {
return ['active', 'waiting', 'waiting-children', 'prioritized', 'completed', 'failed', 'delayed', 'paused']
}
}
15 changes: 12 additions & 3 deletions packages/api/typings/app.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { RedisInfo } from 'redis-info';
import { STATUSES } from '../src/constants/statuses';
import { STATUSES, STATUSES_EXT } from '../src/constants/statuses';
import { BaseAdapter } from '../src/queueAdapters/base';

export type JobCleanStatus = 'completed' | 'wait' | 'active' | 'delayed' | 'failed';

export type JobRetryStatus = 'completed' | 'failed';

export type Status = keyof typeof STATUSES;
type Library = 'bull' | 'bullmq';

export type JobStatus = keyof Omit<typeof STATUSES, 'latest'>;
export type Status<Lib extends Library = 'bullmq'> =
Lib extends 'bullmq' ? keyof typeof STATUSES_EXT:
Lib extends 'bull' ? keyof typeof STATUSES :
never

export type JobStatus<Lib extends Library = 'bullmq'> =
Lib extends 'bullmq' ? keyof Omit<typeof STATUSES_EXT, 'latest'>:
Lib extends 'bull' ? keyof Omit<typeof STATUSES, 'latest'>:
never

export type JobCounts = Record<Status, number>;

Expand Down Expand Up @@ -96,6 +104,7 @@ export interface AppQueue {
description?: string;
counts: Record<Status, number>;
jobs: AppJob[];
possibleStatuses: Status[];
pagination: Pagination;
readOnlyMode: boolean;
allowRetries: boolean;
Expand Down
6 changes: 2 additions & 4 deletions packages/ui/src/components/StatusMenu/StatusMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { STATUSES } from '@bull-board/api/src/constants/statuses';
import { AppQueue } from '@bull-board/api/typings/app';
import React from 'react';
import { NavLink, useRouteMatch } from 'react-router-dom';
import { STATUS_LIST } from '../../constants/status-list';
import { QueueDropdownActions } from '../QueueDropdownActions/QueueDropdownActions';
import s from './StatusMenu.module.css';

Expand All @@ -11,8 +9,8 @@ export const StatusMenu = ({ queue, actions }: { queue: AppQueue; actions: any }

return (
<div className={s.statusMenu}>
{STATUS_LIST.map((status) => {
const isLatest = status === STATUSES.latest;
{queue.possibleStatuses.map((status) => {
const isLatest = status === 'latest';
const displayStatus = status.toLocaleUpperCase();
return (
<NavLink
Expand Down
12 changes: 0 additions & 12 deletions packages/ui/src/constants/status-list.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/ui/src/hooks/useSelectedStatuses.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { SelectedStatuses, Status } from '../../typings/app';
import { STATUS_LIST } from '../constants/status-list';
import { useActiveQueueName } from './useActiveQueueName';

function getActiveStatus(search: string) {
const query = new URLSearchParams(search);
return (query.get('status') as Status) || STATUS_LIST[0];
return (query.get('status') as Status) || 'latest';
}

export function useSelectedStatuses(): SelectedStatuses {
Expand Down
3 changes: 1 addition & 2 deletions packages/ui/src/utils/links.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { SelectedStatuses } from '../../typings/app';
import { STATUS_LIST } from '../constants/status-list';

export const links = {
queuePage(queueName: string, selectedStatuses: SelectedStatuses = {}): string {
const withoutStatus =
!selectedStatuses[queueName] || selectedStatuses[queueName] === STATUS_LIST[0];
!selectedStatuses[queueName] || selectedStatuses[queueName] === 'latest';
return `/queue/${encodeURIComponent(queueName)}${
withoutStatus ? '' : `?status=${selectedStatuses[queueName]}`
}`;
Expand Down