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

feat: add pause / resume on queue level #309

Merged
merged 2 commits into from
Aug 3, 2021
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
14 changes: 14 additions & 0 deletions packages/api/src/handlers/pauseQueue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { BullBoardRequest, ControllerHandlerReturnType } from '../../typings/app';
import { queueProvider } from '../providers/queue';
import { BaseAdapter } from '../queueAdapters/base';

async function pauseQueue(
_req: BullBoardRequest,
queue: BaseAdapter
): Promise<ControllerHandlerReturnType> {
await queue.pause();

return { status: 200, body: {} };
}

export const pauseQueueHandler = queueProvider(pauseQueue);
2 changes: 2 additions & 0 deletions packages/api/src/handlers/queues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ async function getAppQueues(

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

const isPaused = await queue.isPaused();
const pagination = getPagination(status, counts, currentPage);
const jobs = await queue.getJobs(status, pagination.range.start, pagination.range.end);

Expand All @@ -112,6 +113,7 @@ async function getAppQueues(
jobs: jobs.filter(Boolean).map((job) => formatJob(job, queue)),
pagination,
readOnlyMode: queue.readOnlyMode,
isPaused,
};
})
);
Expand Down
14 changes: 14 additions & 0 deletions packages/api/src/handlers/resumeQueue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { BullBoardRequest, ControllerHandlerReturnType } from '../../typings/app';
import { queueProvider } from '../providers/queue';
import { BaseAdapter } from '../queueAdapters/base';

async function resumeQueue(
_req: BullBoardRequest,
queue: BaseAdapter
): Promise<ControllerHandlerReturnType> {
await queue.resume();

return { status: 200, body: {} };
}

export const resumeQueueHandler = queueProvider(resumeQueue);
3 changes: 3 additions & 0 deletions packages/api/src/queueAdapters/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,7 @@ export abstract class BaseAdapter {
public abstract getName(): string;

public abstract getRedisInfo(): Promise<string>;
public abstract isPaused(): Promise<boolean>;
public abstract pause(): Promise<void>;
public abstract resume(): Promise<void>;
}
12 changes: 12 additions & 0 deletions packages/api/src/queueAdapters/bull.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,16 @@ export class BullAdapter extends BaseAdapter {
public getJobLogs(id: string): Promise<string[]> {
return this.queue.getJobLogs(id).then(({ logs }) => logs);
}

public isPaused(): Promise<boolean> {
return this.queue.isPaused();
}

public pause(): Promise<void> {
return this.queue.pause();
}

public resume(): Promise<void> {
return this.queue.resume();
}
}
12 changes: 12 additions & 0 deletions packages/api/src/queueAdapters/bullMQ.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,16 @@ export class BullMQAdapter extends BaseAdapter {
public getJobLogs(id: string): Promise<string[]> {
return this.queue.getJobLogs(id).then(({ logs }) => logs);
}

public isPaused(): Promise<boolean> {
return this.queue.isPaused();
}

public pause(): Promise<void> {
return this.queue.pause();
}

public resume(): Promise<void> {
return this.queue.resume();
}
}
30 changes: 21 additions & 9 deletions packages/api/src/routes.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { AppRouteDefs } from '../typings/app';
import { cleanAllHandler } from './handlers/cleanAll';
import { cleanJobHandler } from './handlers/cleanJob';
import { entryPoint } from './handlers/entryPoint';
import { jobLogsHandler } from './handlers/jobLogs';
import { pauseQueueHandler } from './handlers/pauseQueue';
import { promoteJobHandler } from './handlers/promotJob';
import { queuesHandler } from './handlers/queues';
import { resumeQueueHandler } from './handlers/resumeQueue';
import { retryAllHandler } from './handlers/retryAll';
import { cleanAllHandler } from './handlers/cleanAll';
import { retryJobHandler } from './handlers/retryJob';
import { cleanJobHandler } from './handlers/cleanJob';
import { promoteJobHandler } from './handlers/promotJob';
import { jobLogsHandler } from './handlers/jobLogs';

export const appRoutes: AppRouteDefs = {
entryPoint: {
Expand All @@ -16,6 +18,11 @@ export const appRoutes: AppRouteDefs = {
},
api: [
{ method: 'get', route: '/api/queues', handler: queuesHandler },
{
method: 'get',
route: '/api/queues/:queueName/:jobId/logs',
handler: jobLogsHandler,
},
{
method: 'put',
route: '/api/queues/:queueName/retry',
Expand All @@ -26,6 +33,16 @@ export const appRoutes: AppRouteDefs = {
route: '/api/queues/:queueName/clean/:queueStatus',
handler: cleanAllHandler,
},
{
method: 'put',
route: '/api/queues/:queueName/pause',
handler: pauseQueueHandler,
},
{
method: 'put',
route: '/api/queues/:queueName/resume',
handler: resumeQueueHandler,
},
{
method: 'put',
route: '/api/queues/:queueName/:jobId/retry',
Expand All @@ -41,10 +58,5 @@ export const appRoutes: AppRouteDefs = {
route: '/api/queues/:queueName/:jobId/promote',
handler: promoteJobHandler,
},
{
method: 'get',
route: '/api/queues/:queueName/:jobId/logs',
handler: jobLogsHandler,
},
],
};
4 changes: 4 additions & 0 deletions packages/api/tests/api/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ describe('happy', () => {
"paused": 0,
"waiting": 0,
},
"isPaused": false,
"jobs": Array [],
"name": "Paint",
"pagination": Object {
Expand Down Expand Up @@ -133,6 +134,7 @@ describe('happy', () => {
"paused": 0,
"waiting": 0,
},
"isPaused": false,
"jobs": Array [],
"name": "Code",
"pagination": Object {
Expand Down Expand Up @@ -199,6 +201,7 @@ describe('happy', () => {
"paused": 0,
"waiting": 0,
},
"isPaused": false,
"jobs": Array [],
"name": "AddedQueue",
"pagination": Object {
Expand Down Expand Up @@ -331,6 +334,7 @@ describe('happy', () => {
"paused": 0,
"waiting": 0,
},
"isPaused": false,
"jobs": Array [],
"name": "Code",
"pagination": Object {
Expand Down
1 change: 1 addition & 0 deletions packages/api/typings/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export interface AppQueue {
jobs: AppJob[];
pagination: Pagination;
readOnlyMode: boolean;
isPaused: boolean;
}

export type HTTPMethod = 'get' | 'post' | 'put';
Expand Down
3 changes: 2 additions & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
},
"dependencies": {
"@bull-board/api": "3.3.3",
"@radix-ui/react-alert-dialog": "^0.0.19"
"@radix-ui/react-alert-dialog": "^0.0.19",
"@radix-ui/react-dropdown-menu": "^0.0.22"
},
"devDependencies": {
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const App = ({ api }: { api: Api }) => {
)}
</div>
</main>
<Menu queues={state.data?.queues.map((q) => q.name)} selectedStatuses={selectedStatuses} />
<Menu queues={state.data?.queues} selectedStatuses={selectedStatuses} />
<ToastContainer />
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@

.overlay[data-state='open'],
.contentWrapper[data-state='open'] {
animation: fadeIn 250ms ease-out;
animation: fadeIn 150ms ease-out;
}

.overlay[data-state='closed'],
.contentWrapper[data-state='closed'] {
animation: fadeOut 250ms ease-in;
animation: fadeOut 150ms ease-in;
}

.overlay {
Expand Down
11 changes: 11 additions & 0 deletions packages/ui/src/components/Icons/EllipsisVertical.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';

export const EllipsisVerticalIcon = () => (
<svg aria-hidden="true" role="img"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 512"
>
<path
d="M96 184c39.8 0 72 32.2 72 72s-32.2 72-72 72-72-32.2-72-72 32.2-72 72-72zM24 80c0 39.8 32.2 72 72 72s72-32.2 72-72S135.8 8 96 8 24 40.2 24 80zm0 352c0 39.8 32.2 72 72 72s72-32.2 72-72-32.2-72-72-72-72 32.2-72 72z"
></path>
</svg>
);
10 changes: 10 additions & 0 deletions packages/ui/src/components/Icons/Pause.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';

export const PauseIcon = () => (
<svg aria-hidden="true" focusable="false" role="img"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path
d="M144 479H48c-26.5 0-48-21.5-48-48V79c0-26.5 21.5-48 48-48h96c26.5 0 48 21.5 48 48v352c0 26.5-21.5 48-48 48zm304-48V79c0-26.5-21.5-48-48-48h-96c-26.5 0-48 21.5-48 48v352c0 26.5 21.5 48 48 48h96c26.5 0 48-21.5 48-48z"
></path>
</svg>
);
10 changes: 10 additions & 0 deletions packages/ui/src/components/Icons/Play.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';

export const PlayIcon = () => (
<svg aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512">
<path
d="M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z"
></path>
</svg>
);
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

.button.default > svg {
width: 1.25em;
height: 1.25em;
vertical-align: middle;
display: inline-block;
fill: #718096;
Expand Down
7 changes: 7 additions & 0 deletions packages/ui/src/components/Menu/Menu.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,10 @@
.appVersion {
text-align: center;
}

.isPaused {
color: #828e97;
font-size: 0.833em;
display: block;
margin-bottom: -0.75em;
}
9 changes: 5 additions & 4 deletions packages/ui/src/components/Menu/Menu.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import { AppQueue } from '@bull-board/api/typings/app';
import React from 'react';
import { NavLink } from 'react-router-dom';
import { STATUS_LIST } from '../../constants/status-list';
import { Store } from '../../hooks/useStore';
import s from './Menu.module.css';
import { STATUS_LIST } from '../../constants/status-list';

export const Menu = ({
queues,
selectedStatuses,
}: {
queues: string[] | undefined;
queues: AppQueue[] | undefined;
selectedStatuses: Store['selectedStatuses'];
}) => (
<aside className={s.aside}>
<div>QUEUES</div>
<nav>
{!!queues && (
<ul className={s.menu}>
{queues.map((queueName) => (
{queues.map(({ name: queueName, isPaused }) => (
<li key={queueName}>
<NavLink
to={`/queue/${encodeURIComponent(queueName)}${
Expand All @@ -27,7 +28,7 @@ export const Menu = ({
activeClassName={s.active}
title={queueName}
>
{queueName}
{queueName} {isPaused && <span className={s.isPaused}>[ Paused ]</span>}
</NavLink>
</li>
))}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.trigger {
padding: .5em .65em;
margin-bottom: 0.25em;
justify-self: flex-end;
}

.content {
background: #fff;
box-shadow: 0 2px 3px 0 rgba(34,36,38 ,0.15);
border: 1px solid rgba(34,36,38,.15);
border-radius: .28571429rem;
padding-top: .25rem;
padding-bottom: .25rem;
font-size: .875rem;
line-height: 1.25rem;
font-weight: 400;
min-width: 150px;
}


.item {
display: block;
color: rgba(0,0,0,.87);
padding: .5rem 1rem;
font-weight: 400;
white-space: nowrap;
cursor: pointer;
}

.item > svg {
float: none;
margin-right: .5rem;
width: 1.18em;
height: 1em;
vertical-align: middle;
fill: #718096;
}

.item:hover {
color: rgba(0,0,0,.95);
background: #e2e8f0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { AppQueue } from '@bull-board/api/typings/app';
import { Content, Item, Root, Trigger } from '@radix-ui/react-dropdown-menu';
import React from 'react';
import { Store } from '../../hooks/useStore';
import { EllipsisVerticalIcon } from '../Icons/EllipsisVertical';
import { PauseIcon } from '../Icons/Pause';
import { PlayIcon } from '../Icons/Play';
import { Button } from '../JobCard/Button/Button';
import s from './QueueDropdownActions.module.css';

export const QueueDropdownActions = ({
queue,
actions,
}: {
queue: AppQueue;
actions: Store['actions'];
}) => (
<Root>
<Trigger as={Button} className={s.trigger}>
<EllipsisVerticalIcon />
</Trigger>

<Content className={s.content} align="end">
<Item
className={s.item}
onSelect={queue.isPaused ? actions.resumeQueue(queue.name) : actions.pauseQueue(queue.name)}
>
{queue.isPaused ? (
<>
<PlayIcon />
Resume
</>
) : (
<>
<PauseIcon />
Pause
</>
)}
</Item>
</Content>
</Root>
);
Loading