Skip to content

Commit

Permalink
[ray dashboard] Fix sorting order on cluster page (ray-project#42929)
Browse files Browse the repository at this point in the history
Sets the default sorting order of nodes on the clusters page to (1) alive nodes first then alphabetically for other states (2) head node before worker nodes (3) alphabetical by node ID.
  • Loading branch information
nikitavemuri authored Feb 2, 2024
1 parent c3de7f8 commit c202890
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 6 deletions.
17 changes: 11 additions & 6 deletions dashboard/client/src/pages/node/hook/useNodeList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,17 @@ export const useNodeList = () => {
}))
.sort(sorterFunc);

const sortedList = _.sortBy(nodeListWithAdditionalInfo, [
(obj) => !obj.raylet.isHeadNode,
// sort by alive first, then alphabetically for other states
(obj) => (obj.raylet.state === "ALIVE" ? "0" : obj.raylet.state),
(obj) => obj.raylet.nodeId,
]);
const sortedList = _.sortBy(nodeListWithAdditionalInfo, (node) => {
// After sorting by user specified field, stable sort by
// 1) Alive nodes first then alphabetically for other states
// 2) Head node
// 3) Alphabetical by node id
const nodeStateOrder =
node.raylet.state === "ALIVE" ? "0" : node.raylet.state;
const isHeadNodeOrder = node.raylet.isHeadNode ? "0" : "1";
const nodeIdOrder = node.raylet.nodeId;
return [nodeStateOrder, isHeadNodeOrder, nodeIdOrder];
});

return {
nodeList: sortedList.filter((node) =>
Expand Down
137 changes: 137 additions & 0 deletions dashboard/client/src/pages/node/useNodeList.component.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { render, screen } from "@testing-library/react";
import React from "react";
import { MemoryRouter } from "react-router-dom";
import useSWR from "swr";
import { NodeDetail } from "../../type/node";
import { useNodeList } from "./hook/useNodeList";

jest.mock("swr");
const useSWRMocked = jest.mocked(useSWR);

const NODE: NodeDetail = {
hostname: "test-hostname",
ip: "192.168.0.1",
cpu: 15,
mem: [100, 95, 5],
state: "ALIVE",
disk: {
"/": {
used: 20000000,
total: 200000000,
free: 180000000,
percent: 10,
},
"/tmp": {
used: 0,
total: 200,
free: 200,
percent: 0,
},
},
networkSpeed: [5, 10],
raylet: {
state: "ALIVE",
nodeId: "1234567890ab",
isHeadNode: true,
numWorkers: 0,
pid: 2345,
startTime: 100,
terminateTime: -1,
brpcPort: 3456,
nodeManagerPort: 5890,
objectStoreAvailableMemory: 40,
objectStoreUsedMemory: 10,
},
} as NodeDetail;

const aliveHeadNode = { ...NODE, hostname: "test-hostname-alive-head-node" };
const deadHeadNode = {
...NODE,
hostname: "test-hostname-dead-head-node",
state: "DEAD",
raylet: {
state: "DEAD",
nodeId: "1234567890ab",
isHeadNode: false,
numWorkers: 0,
pid: 2345,
startTime: 100,
terminateTime: -1,
brpcPort: 3456,
nodeManagerPort: 5890,
objectStoreAvailableMemory: 40,
objectStoreUsedMemory: 10,
},
};
const aliveWorkerNode1 = {
...NODE,
hostname: "test-hostname-worker1",
raylet: {
state: "ALIVE",
nodeId: "1234567890ab",
isHeadNode: false,
numWorkers: 0,
pid: 2345,
startTime: 100,
terminateTime: -1,
brpcPort: 3456,
nodeManagerPort: 5890,
objectStoreAvailableMemory: 40,
objectStoreUsedMemory: 10,
},
};
const aliveWorkerNode2 = {
...NODE,
hostname: "test-hostname-worker2",
raylet: {
state: "ALIVE",
nodeId: "1234567890ac",
isHeadNode: false,
numWorkers: 0,
pid: 2345,
startTime: 100,
terminateTime: -1,
brpcPort: 3456,
nodeManagerPort: 5890,
objectStoreAvailableMemory: 40,
objectStoreUsedMemory: 10,
},
};

describe("useNodeList", () => {
it("verify default sort order of useNodeList", () => {
useSWRMocked.mockReturnValue({
data: {
summary: [
deadHeadNode,
aliveWorkerNode2,
aliveHeadNode,
aliveWorkerNode1,
],
nodeLogicalResources: undefined,
},
isLoading: false,
} as any);

const TestComponent = () => {
const { nodeList } = useNodeList();
const nodeHostNames = nodeList.map((e) => e.hostname);
return <div data-testid="nodeHostNames">{nodeHostNames}</div>;
};

render(
<MemoryRouter>
<TestComponent />
</MemoryRouter>,
);

const nodeHostNames = screen.getByTestId("nodeHostNames");
const expectedOrderNodeList = [
aliveHeadNode.hostname,
aliveWorkerNode1.hostname,
aliveWorkerNode2.hostname,
deadHeadNode.hostname,
];
expect(nodeHostNames.textContent).toEqual(expectedOrderNodeList.join(""));
});
});

0 comments on commit c202890

Please sign in to comment.